Feature: Twilio Whatsapp Integration (#779)
Twilio Whatsapp Integration Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
parent
168042f9a4
commit
0cb7333977
23 changed files with 238 additions and 81 deletions
1
Gemfile
1
Gemfile
|
@ -17,6 +17,7 @@ gem 'jbuilder'
|
|||
gem 'kaminari'
|
||||
gem 'responders'
|
||||
gem 'rest-client'
|
||||
gem 'telephone_number'
|
||||
gem 'time_diff'
|
||||
gem 'tzinfo-data'
|
||||
gem 'valid_email2'
|
||||
|
|
|
@ -448,6 +448,7 @@ GEM
|
|||
faraday
|
||||
inflecto
|
||||
virtus
|
||||
telephone_number (1.4.6)
|
||||
thor (0.20.3)
|
||||
thread_safe (0.3.6)
|
||||
time_diff (0.3.0)
|
||||
|
@ -560,6 +561,7 @@ DEPENDENCIES
|
|||
spring
|
||||
spring-watcher-listen
|
||||
telegram-bot-ruby
|
||||
telephone_number
|
||||
time_diff
|
||||
twilio-ruby (~> 5.32.0)
|
||||
twitty!
|
||||
|
|
|
@ -21,13 +21,14 @@ class ContactBuilder
|
|||
phone_number: contact_attributes[:phone_number],
|
||||
email: contact_attributes[:email],
|
||||
identifier: contact_attributes[:identifier],
|
||||
additional_attributes: contact_attributes[:identifier]
|
||||
additional_attributes: contact_attributes[:additional_attributes]
|
||||
)
|
||||
contact_inbox = ::ContactInbox.create!(
|
||||
contact_id: contact.id,
|
||||
inbox_id: inbox.id,
|
||||
source_id: source_id
|
||||
)
|
||||
|
||||
::ContactAvatarJob.perform_later(contact, contact_attributes[:avatar_url]) if contact_attributes[:avatar_url]
|
||||
contact_inbox
|
||||
rescue StandardError => e
|
||||
|
|
|
@ -15,7 +15,6 @@ class Messages::Outgoing::NormalBuilder
|
|||
|
||||
def perform
|
||||
@message = @conversation.messages.build(message_params)
|
||||
@message.save
|
||||
if @attachments.present?
|
||||
@attachments.each do |uploaded_attachment|
|
||||
attachment = @message.attachments.new(
|
||||
|
@ -24,8 +23,8 @@ class Messages::Outgoing::NormalBuilder
|
|||
)
|
||||
attachment.file.attach(uploaded_attachment)
|
||||
end
|
||||
@message.save
|
||||
end
|
||||
@message.save
|
||||
@message
|
||||
end
|
||||
|
||||
|
|
|
@ -2,13 +2,15 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::BaseControlle
|
|||
before_action :authorize_request
|
||||
|
||||
def create
|
||||
authenticate_twilio
|
||||
build_inbox
|
||||
setup_webhooks
|
||||
rescue Twilio::REST::TwilioError => e
|
||||
render_could_not_create_error(e.message)
|
||||
rescue StandardError => e
|
||||
render_could_not_create_error(e.message)
|
||||
ActiveRecord::Base.transaction do
|
||||
authenticate_twilio
|
||||
build_inbox
|
||||
setup_webhooks if @twilio_channel.sms?
|
||||
rescue Twilio::REST::TwilioError => e
|
||||
render_could_not_create_error(e.message)
|
||||
rescue StandardError => e
|
||||
render_could_not_create_error(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -26,25 +28,30 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::BaseControlle
|
|||
::Twilio::WebhookSetupService.new(inbox: @inbox).perform
|
||||
end
|
||||
|
||||
def phone_number
|
||||
medium == 'sms' ? permitted_params[:phone_number] : "whatsapp:#{permitted_params[:phone_number]}"
|
||||
end
|
||||
|
||||
def medium
|
||||
permitted_params[:medium]
|
||||
end
|
||||
|
||||
def build_inbox
|
||||
ActiveRecord::Base.transaction do
|
||||
twilio_sms = current_account.twilio_sms.create(
|
||||
account_sid: permitted_params[:account_sid],
|
||||
auth_token: permitted_params[:auth_token],
|
||||
phone_number: permitted_params[:phone_number]
|
||||
)
|
||||
@inbox = current_account.inboxes.create(
|
||||
name: permitted_params[:name],
|
||||
channel: twilio_sms
|
||||
)
|
||||
rescue StandardError => e
|
||||
render_could_not_create_error(e.message)
|
||||
end
|
||||
@twilio_channel = current_account.twilio_sms.create!(
|
||||
account_sid: permitted_params[:account_sid],
|
||||
auth_token: permitted_params[:auth_token],
|
||||
phone_number: phone_number,
|
||||
medium: medium
|
||||
)
|
||||
@inbox = current_account.inboxes.create(
|
||||
name: permitted_params[:name],
|
||||
channel: @twilio_channel
|
||||
)
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params.require(:twilio_channel).permit(
|
||||
:account_id, :phone_number, :account_sid, :auth_token, :name
|
||||
:account_id, :phone_number, :account_sid, :auth_token, :name, :medium
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,7 +23,9 @@ class Twilio::CallbackController < ApplicationController
|
|||
:FromZip,
|
||||
:Body,
|
||||
:ToCountry,
|
||||
:FromState
|
||||
:FromState,
|
||||
:MediaUrl0,
|
||||
:MediaContentType0
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
BIN
app/javascript/dashboard/assets/images/channels/whatsapp.png
Normal file
BIN
app/javascript/dashboard/assets/images/channels/whatsapp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
|
@ -33,6 +33,14 @@
|
|||
:style="badgeStyle"
|
||||
src="~dashboard/assets/images/twitter-badge.png"
|
||||
/>
|
||||
|
||||
<img
|
||||
v-if="badge === 'Channel::TwilioSms'"
|
||||
id="badge"
|
||||
class="source-badge"
|
||||
:style="badgeStyle"
|
||||
src="~dashboard/assets/images/channels/whatsapp.png"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<file-upload
|
||||
v-if="showFileUpload"
|
||||
:size="4096 * 4096"
|
||||
accept="jpg,jpeg,png,mp3,ogg,amr,pdf,mp4"
|
||||
@input-file="onFileUpload"
|
||||
>
|
||||
<i
|
||||
|
@ -142,7 +143,10 @@ export default {
|
|||
return 10000;
|
||||
},
|
||||
showFileUpload() {
|
||||
return this.channelType === 'Channel::WebWidget';
|
||||
return (
|
||||
this.channelType === 'Channel::WebWidget' ||
|
||||
this.channelType === 'Channel::TwilioSms'
|
||||
);
|
||||
},
|
||||
replyButtonLabel() {
|
||||
if (this.isPrivate) {
|
||||
|
@ -295,6 +299,9 @@ export default {
|
|||
},
|
||||
|
||||
onFileUpload(file) {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
this.isUploading.image = true;
|
||||
this.$store
|
||||
.dispatch('sendAttachment', [this.currentChat.id, { file: file.file }])
|
||||
|
|
|
@ -6,10 +6,26 @@
|
|||
"404": "Diesem Konto sind keine Posteingänge zugeordnet."
|
||||
},
|
||||
"CREATE_FLOW": [
|
||||
{ "title": "Wählen Sie Kanal", "route": "settings_inbox_new", "body": "Wählen Sie den Anbieter, den Sie in Chatwoot integrieren möchten." },
|
||||
{ "title": "Posteingang erstellen", "route": "settings_inboxes_page_channel", "body": "Authentifizieren Sie Ihr Konto und erstellen Sie einen Posteingang." },
|
||||
{ "title": "Agenten hinzufügen", "route": "settings_inboxes_add_agents", "body": "Fügen Sie dem erstellten Posteingang Agenten hinzu." },
|
||||
{ "title": "Voila!", "route": "settings_inbox_finish", "body": "Sie sind bereit zu gehen!" }
|
||||
{
|
||||
"title": "Wählen Sie Kanal",
|
||||
"route": "settings_inbox_new",
|
||||
"body": "Wählen Sie den Anbieter, den Sie in Chatwoot integrieren möchten."
|
||||
},
|
||||
{
|
||||
"title": "Posteingang erstellen",
|
||||
"route": "settings_inboxes_page_channel",
|
||||
"body": "Authentifizieren Sie Ihr Konto und erstellen Sie einen Posteingang."
|
||||
},
|
||||
{
|
||||
"title": "Agenten hinzufügen",
|
||||
"route": "settings_inboxes_add_agents",
|
||||
"body": "Fügen Sie dem erstellten Posteingang Agenten hinzu."
|
||||
},
|
||||
{
|
||||
"title": "Voila!",
|
||||
"route": "settings_inbox_finish",
|
||||
"body": "Sie sind bereit zu gehen!"
|
||||
}
|
||||
],
|
||||
"ADD": {
|
||||
"FB": {
|
||||
|
@ -33,12 +49,11 @@
|
|||
"LABEL": "Widget Farbe",
|
||||
"PLACEHOLDER": "Aktualisieren Sie die im Widget verwendete Widget-Farbe"
|
||||
},
|
||||
"SUBMIT_BUTTON":"Posteingang erstellen"
|
||||
"SUBMIT_BUTTON": "Posteingang erstellen"
|
||||
},
|
||||
|
||||
"TWILIO": {
|
||||
"TITLE": "Twilio SMS Channel",
|
||||
"DESC": "Integrieren Sie Twilio und unterstützen Sie Ihre Kunden per SMS.",
|
||||
"TITLE": "Twilio SMS/Whatsapp Channel",
|
||||
"DESC": "Integrieren Sie Twilio und unterstützen Sie Ihre Kunden per SMS/Whatsapp.",
|
||||
"ACCOUNT_SID": {
|
||||
"LABEL": "Account SID",
|
||||
"PLACEHOLDER": "Bitte geben Sie Ihre Twilio Account SID ein",
|
||||
|
@ -76,7 +91,7 @@
|
|||
"TITLE": "Posteingangsdetails",
|
||||
"DESC": "Wählen Sie aus der Dropdown-Liste die Facebook-Seite aus, zu der Sie eine Verbindung zu Chatwoot herstellen möchten. Sie können Ihrem Posteingang auch einen benutzerdefinierten Namen geben, um ihn besser identifizieren zu können."
|
||||
},
|
||||
"FINISH":{
|
||||
"FINISH": {
|
||||
"TITLE": "Geschafft!",
|
||||
"DESC": "Sie haben die Integration Ihrer Facebook-Seite in Chatwoot erfolgreich abgeschlossen. Wenn ein Kunde das nächste Mal eine Nachricht an Ihre Seite sendet, wird die Konversation automatisch in Ihrem Posteingang angezeigt. <br> Wir stellen Ihnen außerdem ein Widget-Skript zur Verfügung, das Sie ganz einfach zu Ihrer Website hinzufügen können. Sobald dies auf Ihrer Website live ist, können Kunden Ihnen ohne Hilfe eines externen Tools direkt von Ihrer Website aus eine Nachricht senden, und die Konversation wird direkt hier auf Chatwoot angezeigt. <br> Cool, oder? Nun, wir versuchen es auf jeden Fall :)"
|
||||
}
|
||||
|
|
|
@ -6,10 +6,26 @@
|
|||
"404": "There are no inboxes attached to this account."
|
||||
},
|
||||
"CREATE_FLOW": [
|
||||
{ "title": "Choose Channel", "route": "settings_inbox_new", "body": "Choose the provider you want to integrate with Chatwoot." },
|
||||
{ "title": "Create Inbox", "route": "settings_inboxes_page_channel", "body": "Authenticate your account and create an inbox." },
|
||||
{ "title": "Add Agents", "route": "settings_inboxes_add_agents", "body": "Add agents to the created inbox." },
|
||||
{ "title": "Voila!", "route": "settings_inbox_finish", "body": "You are all set to go!" }
|
||||
{
|
||||
"title": "Choose Channel",
|
||||
"route": "settings_inbox_new",
|
||||
"body": "Choose the provider you want to integrate with Chatwoot."
|
||||
},
|
||||
{
|
||||
"title": "Create Inbox",
|
||||
"route": "settings_inboxes_page_channel",
|
||||
"body": "Authenticate your account and create an inbox."
|
||||
},
|
||||
{
|
||||
"title": "Add Agents",
|
||||
"route": "settings_inboxes_add_agents",
|
||||
"body": "Add agents to the created inbox."
|
||||
},
|
||||
{
|
||||
"title": "Voila!",
|
||||
"route": "settings_inbox_finish",
|
||||
"body": "You are all set to go!"
|
||||
}
|
||||
],
|
||||
"ADD": {
|
||||
"FB": {
|
||||
|
@ -46,16 +62,20 @@
|
|||
"LABEL": "Widget Color",
|
||||
"PLACEHOLDER": "Update the widget color used in widget"
|
||||
},
|
||||
"SUBMIT_BUTTON":"Create inbox"
|
||||
"SUBMIT_BUTTON": "Create inbox"
|
||||
},
|
||||
"TWILIO": {
|
||||
"TITLE": "Twilio SMS Channel",
|
||||
"DESC": "Integrate Twilio and start supporting your customers via SMS.",
|
||||
"TITLE": "Twilio SMS/Whatsapp Channel",
|
||||
"DESC": "Integrate Twilio and start supporting your customers via SMS or Whatsapp.",
|
||||
"ACCOUNT_SID": {
|
||||
"LABEL": "Account SID",
|
||||
"PLACEHOLDER": "Please enter your Twilio Account SID",
|
||||
"ERROR": "This field is required"
|
||||
},
|
||||
"CHANNEL_TYPE": {
|
||||
"LABEL": "Channel Type",
|
||||
"ERROR": "Please select your Channel Type"
|
||||
},
|
||||
"AUTH_TOKEN": {
|
||||
"LABEL": "Auth Token",
|
||||
"PLACEHOLDER": "Please enter your Twilio Auth Token",
|
||||
|
@ -88,7 +108,7 @@
|
|||
"TITLE": "Inbox Details",
|
||||
"DESC": "From the dropdown below, select the Facebook Page you want to connect to Chatwoot. You can also give a custom name to your inbox for better identification."
|
||||
},
|
||||
"FINISH":{
|
||||
"FINISH": {
|
||||
"TITLE": "Nailed It!",
|
||||
"DESC": "You have successfully finished integrating your Facebook Page with Chatwoot. Next time a customer messages your Page, the conversation will automatically appear on your inbox.<br>We are also providing you with a widget script that you can easily add to your website. Once this is live on your website, customers can message you right from your website without the help of any external tool and the conversation will appear right here, on Chatwoot.<br>Cool, huh? Well, we sure try to be :)"
|
||||
}
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
>
|
||||
{{ contact.email }}
|
||||
</a>
|
||||
<a
|
||||
v-if="contact.phone_number"
|
||||
:href="`tel:${contact.phone_number}`"
|
||||
class="contact--email"
|
||||
>
|
||||
{{ contact.phone_number }}
|
||||
</a>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
|
@ -211,7 +218,7 @@ export default {
|
|||
text-transform: capitalize;
|
||||
|
||||
font-weight: $font-weight-bold;
|
||||
font-size: $font-size-medium;
|
||||
font-size: $font-size-default;
|
||||
}
|
||||
|
||||
.contact--email {
|
||||
|
|
|
@ -14,9 +14,22 @@
|
|||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.PLACEHOLDER')"
|
||||
@blur="$v.channelName.$touch"
|
||||
/>
|
||||
<span v-if="$v.channelName.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.ERROR') }}
|
||||
</span>
|
||||
<span v-if="$v.channelName.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.medium.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.CHANNEL_TYPE.LABEL') }}
|
||||
<select v-model="medium">
|
||||
<option value="sms">SMS</option>
|
||||
<option value="whatsapp">Whatsapp</option>
|
||||
</select>
|
||||
<span v-if="$v.medium.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_TYPE.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -29,9 +42,9 @@
|
|||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.PLACEHOLDER')"
|
||||
@blur="$v.phoneNumber.$touch"
|
||||
/>
|
||||
<span v-if="$v.phoneNumber.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.ERROR') }}
|
||||
</span>
|
||||
<span v-if="$v.phoneNumber.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -44,9 +57,9 @@
|
|||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.PLACEHOLDER')"
|
||||
@blur="$v.accountSID.$touch"
|
||||
/>
|
||||
<span v-if="$v.accountSID.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.ERROR') }}
|
||||
</span>
|
||||
<span v-if="$v.accountSID.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-8 columns">
|
||||
|
@ -58,9 +71,9 @@
|
|||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.PLACEHOLDER')"
|
||||
@blur="$v.authToken.$touch"
|
||||
/>
|
||||
<span v-if="$v.authToken.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.ERROR') }}
|
||||
</span>
|
||||
<span v-if="$v.authToken.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -92,6 +105,7 @@ export default {
|
|||
return {
|
||||
accountSID: '',
|
||||
authToken: '',
|
||||
medium: '',
|
||||
channelName: '',
|
||||
phoneNumber: '',
|
||||
};
|
||||
|
@ -106,6 +120,7 @@ export default {
|
|||
phoneNumber: { required, shouldStartWithPlusSign },
|
||||
authToken: { required },
|
||||
accountSID: { required },
|
||||
medium: { required },
|
||||
},
|
||||
methods: {
|
||||
async createChannel() {
|
||||
|
@ -120,6 +135,7 @@ export default {
|
|||
{
|
||||
twilio_channel: {
|
||||
name: this.channelName,
|
||||
medium: this.medium,
|
||||
account_sid: this.accountSID,
|
||||
auth_token: this.authToken,
|
||||
phone_number: this.phoneNumber,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# id :bigint not null, primary key
|
||||
# account_sid :string not null
|
||||
# auth_token :string not null
|
||||
# medium :integer default("sms")
|
||||
# phone_number :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
|
@ -23,6 +24,8 @@ class Channel::TwilioSms < ApplicationRecord
|
|||
validates :auth_token, presence: true
|
||||
validates :phone_number, uniqueness: { scope: :account_id }, presence: true
|
||||
|
||||
enum medium: { sms: 0, whatsapp: 1 }
|
||||
|
||||
belongs_to :account
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
|
|
|
@ -70,11 +70,12 @@ class Message < ApplicationRecord
|
|||
has_many :attachments, dependent: :destroy, autosave: true, before_add: :validate_attachments_limit
|
||||
|
||||
after_create :reopen_conversation,
|
||||
:dispatch_event,
|
||||
:send_reply,
|
||||
:execute_message_template_hooks,
|
||||
:notify_via_mail
|
||||
|
||||
# we need to wait for the active storage attachments to be available
|
||||
after_create_commit :dispatch_event, :send_reply
|
||||
|
||||
after_update :dispatch_update_event
|
||||
|
||||
def channel_token
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
class Twilio::IncomingMessageService
|
||||
include ::FileTypeHelper
|
||||
|
||||
pattr_initialize [:params!]
|
||||
|
||||
def perform
|
||||
set_contact
|
||||
set_conversation
|
||||
@conversation.messages.create(
|
||||
@message = @conversation.messages.create(
|
||||
content: params[:Body],
|
||||
account_id: @inbox.account_id,
|
||||
inbox_id: @inbox.id,
|
||||
|
@ -12,6 +14,7 @@ class Twilio::IncomingMessageService
|
|||
contact_id: @contact.id,
|
||||
source_id: params[:SmsSid]
|
||||
)
|
||||
attach_files
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -31,6 +34,14 @@ class Twilio::IncomingMessageService
|
|||
@account ||= inbox.account
|
||||
end
|
||||
|
||||
def phone_number
|
||||
twilio_inbox.sms? ? params[:From] : params[:From].gsub('whatsapp:', '')
|
||||
end
|
||||
|
||||
def formatted_phone_number
|
||||
TelephoneNumber.parse(phone_number).international_number
|
||||
end
|
||||
|
||||
def set_contact
|
||||
contact_inbox = ::ContactBuilder.new(
|
||||
source_id: params[:From],
|
||||
|
@ -61,17 +72,40 @@ class Twilio::IncomingMessageService
|
|||
|
||||
def contact_attributes
|
||||
{
|
||||
name: params[:From],
|
||||
phone_number: params[:From],
|
||||
contact_attributes: additional_attributes
|
||||
name: formatted_phone_number,
|
||||
phone_number: phone_number,
|
||||
additional_attributes: additional_attributes
|
||||
}
|
||||
end
|
||||
|
||||
def additional_attributes
|
||||
{
|
||||
from_zip_code: params[:FromZip],
|
||||
from_country: params[:FromCountry],
|
||||
from_state: params[:FromState]
|
||||
}
|
||||
if twilio_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!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,11 +7,7 @@ class Twilio::OutgoingMessageService
|
|||
return if inbox.channel.class.to_s != 'Channel::TwilioSms'
|
||||
return unless message.outgoing?
|
||||
|
||||
twilio_message = client.messages.create(
|
||||
body: message.content,
|
||||
from: channel.phone_number,
|
||||
to: contact.phone_number
|
||||
)
|
||||
twilio_message = client.messages.create(message_params)
|
||||
message.update!(source_id: twilio_message.sid)
|
||||
end
|
||||
|
||||
|
@ -19,6 +15,21 @@ class Twilio::OutgoingMessageService
|
|||
|
||||
delegate :conversation, to: :message
|
||||
delegate :contact, to: :conversation
|
||||
delegate :contact_inbox, to: :conversation
|
||||
|
||||
def message_params
|
||||
params = {
|
||||
body: message.content,
|
||||
from: channel.phone_number,
|
||||
to: contact_inbox.source_id
|
||||
}
|
||||
params[:media_url] = attachments if channel.whatsapp? && message.attachments.present?
|
||||
params
|
||||
end
|
||||
|
||||
def attachments
|
||||
message.attachments.map(&:file_url)
|
||||
end
|
||||
|
||||
def inbox
|
||||
@inbox ||= message.inbox
|
||||
|
|
5
db/migrate/20200429082655_add_medium_to_twilio_sms.rb
Normal file
5
db/migrate/20200429082655_add_medium_to_twilio_sms.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddMediumToTwilioSms < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :channel_twilio_sms, :medium, :integer, index: true, default: 0
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_04_17_093432) do
|
||||
ActiveRecord::Schema.define(version: 2020_04_29_082655) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -121,6 +121,7 @@ ActiveRecord::Schema.define(version: 2020_04_17_093432) do
|
|||
t.integer "account_id", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.integer "medium", default: 0
|
||||
t.index ["account_id", "phone_number"], name: "index_channel_twilio_sms_on_account_id_and_phone_number", unique: true
|
||||
end
|
||||
|
||||
|
@ -287,11 +288,9 @@ ActiveRecord::Schema.define(version: 2020_04_17_093432) do
|
|||
t.index ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context"
|
||||
t.index ["taggable_id", "taggable_type", "tagger_id", "context"], name: "taggings_idy"
|
||||
t.index ["taggable_id"], name: "index_taggings_on_taggable_id"
|
||||
t.index ["taggable_type", "taggable_id"], name: "index_taggings_on_taggable_type_and_taggable_id"
|
||||
t.index ["taggable_type"], name: "index_taggings_on_taggable_type"
|
||||
t.index ["tagger_id", "tagger_type"], name: "index_taggings_on_tagger_id_and_tagger_type"
|
||||
t.index ["tagger_id"], name: "index_taggings_on_tagger_id"
|
||||
t.index ["tagger_type", "tagger_id"], name: "index_taggings_on_tagger_type_and_tagger_id"
|
||||
end
|
||||
|
||||
create_table "tags", id: :serial, force: :cascade do |t|
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
class LocalResource
|
||||
attr_reader :uri
|
||||
|
||||
def initialize(uri)
|
||||
def initialize(uri, file_type = nil)
|
||||
@uri = URI(uri)
|
||||
@file_type = file_type
|
||||
end
|
||||
|
||||
def file
|
||||
|
@ -23,11 +24,12 @@ class LocalResource
|
|||
io.read.encoding
|
||||
end
|
||||
|
||||
def find_file_type
|
||||
@file_type ? @file_type.split('/').last : Pathname.new(uri.path).extname
|
||||
end
|
||||
|
||||
def tmp_filename
|
||||
[
|
||||
Time.now.to_i.to_s,
|
||||
Pathname.new(uri.path).extname
|
||||
]
|
||||
[Time.now.to_i.to_s, find_file_type].join('.')
|
||||
end
|
||||
|
||||
def tmp_folder
|
||||
|
|
|
@ -21,7 +21,8 @@ RSpec.describe '/api/v1/accounts/{account.id}/channels/twilio_channel', type: :r
|
|||
account_sid: 'sid',
|
||||
auth_token: 'token',
|
||||
phone_number: '+1234567890',
|
||||
name: 'SMS Channel'
|
||||
name: 'SMS Channel',
|
||||
medium: 'sms'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ FactoryBot.define do
|
|||
auth_token { SecureRandom.uuid }
|
||||
account_sid { SecureRandom.uuid }
|
||||
sequence(:phone_number) { |n| "+123456789#{n}1" }
|
||||
medium { :sms }
|
||||
inbox
|
||||
account
|
||||
end
|
||||
|
|
|
@ -10,7 +10,9 @@ describe Twilio::OutgoingMessageService do
|
|||
let!(:account) { create(:account) }
|
||||
let!(:widget_inbox) { create(:inbox, account: account) }
|
||||
let!(:twilio_sms) { create(:channel_twilio_sms, account: account) }
|
||||
let!(:twilio_whatsapp) { create(:channel_twilio_sms, medium: :whatsapp, account: account) }
|
||||
let!(:twilio_inbox) { create(:inbox, channel: twilio_sms, account: account) }
|
||||
let!(:twilio_whatsapp_inbox) { create(:inbox, channel: twilio_whatsapp, account: account) }
|
||||
let!(:contact) { create(:contact, account: account) }
|
||||
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: twilio_inbox) }
|
||||
let(:conversation) { create(:conversation, contact: contact, inbox: twilio_inbox, contact_inbox: contact_inbox) }
|
||||
|
@ -55,5 +57,18 @@ describe Twilio::OutgoingMessageService do
|
|||
expect(outgoing_message.reload.source_id).to eq('1234')
|
||||
end
|
||||
end
|
||||
|
||||
it 'if outgoing message has attachment and is for whatsapp' do
|
||||
# check for message attachment url
|
||||
allow(messages_double).to receive(:create).with(hash_including(media_url: [anything])).and_return(message_record_double)
|
||||
allow(message_record_double).to receive(:sid).and_return('1234')
|
||||
|
||||
message = build(
|
||||
:message, message_type: 'outgoing', inbox: twilio_whatsapp_inbox, account: account, conversation: conversation
|
||||
)
|
||||
attachment = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
attachment.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png')
|
||||
message.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue