feat: Line Channel (#2904)
- Ability to configure line bots as a channel in chatwoot - Receive a message sent to the line bot in chatwoot - Ability to reply to line users from chatwoot fixes: #2738
This commit is contained in:
@@ -92,6 +92,8 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
Current.account.api_channels.create!(permitted_params(Channel::Api::EDITABLE_ATTRS)[:channel].except(:type))
|
||||
when 'email'
|
||||
Current.account.email_channels.create!(permitted_params(Channel::Email::EDITABLE_ATTRS)[:channel].except(:type))
|
||||
when 'line'
|
||||
Current.account.line_channels.create!(permitted_params(Channel::Line::EDITABLE_ATTRS)[:channel].except(:type))
|
||||
when 'telegram'
|
||||
Current.account.telegram_channels.create!(permitted_params(Channel::Telegram::EDITABLE_ATTRS)[:channel].except(:type))
|
||||
end
|
||||
@@ -122,6 +124,8 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
Channel::Email::EDITABLE_ATTRS
|
||||
when 'Channel::Telegram'
|
||||
Channel::Telegram::EDITABLE_ATTRS
|
||||
when 'Channel::Line'
|
||||
Channel::Line::EDITABLE_ATTRS
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
6
app/controllers/webhooks/line_controller.rb
Normal file
6
app/controllers/webhooks/line_controller.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Webhooks::LineController < ActionController::API
|
||||
def process_payload
|
||||
Webhooks::LineEventsJob.perform_later(params: params.to_unsafe_hash, signature: request.headers['x-line-signature'], post_body: request.raw_post)
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
@@ -76,7 +76,16 @@ export default {
|
||||
if (key === 'email') {
|
||||
return this.enabledFeatures.channel_email;
|
||||
}
|
||||
return ['website', 'twilio', 'api', 'whatsapp', 'sms', 'telegram'].includes(key);
|
||||
|
||||
return [
|
||||
'website',
|
||||
'twilio',
|
||||
'api',
|
||||
'whatsapp',
|
||||
'sms',
|
||||
'telegram',
|
||||
'line',
|
||||
].includes(key);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -35,6 +35,13 @@
|
||||
:style="badgeStyle"
|
||||
src="~dashboard/assets/images/channels/whatsapp.png"
|
||||
/>
|
||||
<img
|
||||
v-if="badge === 'Channel::Line'"
|
||||
id="badge"
|
||||
class="source-badge"
|
||||
:style="badgeStyle"
|
||||
src="~dashboard/assets/images/channels/line.png"
|
||||
/>
|
||||
<img
|
||||
v-if="badge === 'Channel::Telegram'"
|
||||
id="badge"
|
||||
|
||||
@@ -172,7 +172,32 @@
|
||||
},
|
||||
"FINISH_MESSAGE": "Start forwarding your emails to the following email address."
|
||||
},
|
||||
"TELEGRAM_CHANNEL": {
|
||||
"LINE_CHANNEL": {
|
||||
"TITLE": "LINE Channel",
|
||||
"DESC": "Integrate with LINE channel and start supporting your customers.",
|
||||
"CHANNEL_NAME": {
|
||||
"LABEL": "Channel Name",
|
||||
"PLACEHOLDER": "Please enter a channel name",
|
||||
"ERROR": "This field is required"
|
||||
},
|
||||
"LINE_CHANNEL_ID": {
|
||||
"LABEL": "LINE Channel ID",
|
||||
"PLACEHOLDER": "LINE Channel ID"
|
||||
},
|
||||
"LINE_CHANNEL_SECRET": {
|
||||
"LABEL": "LINE Channel Secret",
|
||||
"PLACEHOLDER": "LINE Channel Secret"
|
||||
},
|
||||
"LINE_CHANNEL_TOKEN": {
|
||||
"LABEL": "LINE Channel Token",
|
||||
"PLACEHOLDER": "LINE Channel Token"
|
||||
},
|
||||
"SUBMIT_BUTTON": "Create LINE Channel",
|
||||
"API": {
|
||||
"ERROR_MESSAGE": "We were not able to save the LINE channel"
|
||||
}
|
||||
},
|
||||
"TELEGRAM_CHANNEL": {
|
||||
"TITLE": "Telegram Channel",
|
||||
"DESC": "Integrate with Telegram channel and start supporting your customers.",
|
||||
"BOT_TOKEN": {
|
||||
|
||||
@@ -17,7 +17,15 @@
|
||||
<woot-code
|
||||
v-if="isATwilioInbox"
|
||||
lang="html"
|
||||
:script="twilioCallbackURL"
|
||||
:script="currentInbox.webhook_url"
|
||||
>
|
||||
</woot-code>
|
||||
</div>
|
||||
<div class="medium-6 small-offset-3">
|
||||
<woot-code
|
||||
v-if="isALineInbox"
|
||||
lang="html"
|
||||
:script="currentInbox.webhook_url"
|
||||
>
|
||||
</woot-code>
|
||||
</div>
|
||||
@@ -75,6 +83,9 @@ export default {
|
||||
isAEmailInbox() {
|
||||
return this.currentInbox.channel_type === 'Channel::Email';
|
||||
},
|
||||
isALineInbox() {
|
||||
return this.currentInbox.channel_type === 'Channel::Line';
|
||||
},
|
||||
message() {
|
||||
if (this.isATwilioInbox) {
|
||||
return `${this.$t('INBOX_MGMT.FINISH.MESSAGE')}. ${this.$t(
|
||||
|
||||
@@ -5,6 +5,7 @@ import Api from './channels/Api';
|
||||
import Email from './channels/Email';
|
||||
import Sms from './channels/Sms';
|
||||
import Whatsapp from './channels/Whatsapp';
|
||||
import Line from './channels/Line';
|
||||
import Telegram from './channels/Telegram';
|
||||
|
||||
const channelViewList = {
|
||||
@@ -15,6 +16,7 @@ const channelViewList = {
|
||||
email: Email,
|
||||
sms: Sms,
|
||||
whatsapp: Whatsapp,
|
||||
line: Line,
|
||||
telegram: Telegram,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="wizard-body small-9 columns">
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.LINE_CHANNEL.DESC')"
|
||||
/>
|
||||
<form class="row" @submit.prevent="createChannel()">
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.channelName.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.LABEL') }}
|
||||
<input
|
||||
v-model.trim="channelName"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
|
||||
"
|
||||
@blur="$v.channelName.$touch"
|
||||
/>
|
||||
<span v-if="$v.channelName.$error" class="message">{{
|
||||
$t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.ERROR')
|
||||
}}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.lineChannelId.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_ID.LABEL') }}
|
||||
<input
|
||||
v-model.trim="lineChannelId"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_ID.PLACEHOLDER')
|
||||
"
|
||||
@blur="$v.lineChannelId.$touch"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.lineChannelSecret.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_SECRET.LABEL') }}
|
||||
<input
|
||||
v-model.trim="lineChannelSecret"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_SECRET.PLACEHOLDER')
|
||||
"
|
||||
@blur="$v.lineChannelSecret.$touch"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.lineChannelToken.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_TOKEN.LABEL') }}
|
||||
<input
|
||||
v-model.trim="lineChannelToken"
|
||||
type="text"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_TOKEN.PLACEHOLDER')
|
||||
"
|
||||
@blur="$v.lineChannelToken.$touch"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-12 columns">
|
||||
<woot-submit-button
|
||||
:loading="uiFlags.isCreating"
|
||||
:button-text="$t('INBOX_MGMT.ADD.LINE_CHANNEL.SUBMIT_BUTTON')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
import router from '../../../../index';
|
||||
import PageHeader from '../../SettingsSubPageHeader';
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
data() {
|
||||
return {
|
||||
channelName: '',
|
||||
lineChannelId: '',
|
||||
lineChannelSecret: '',
|
||||
lineChannelToken: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'inboxes/getUIFlags',
|
||||
}),
|
||||
},
|
||||
validations: {
|
||||
channelName: { required },
|
||||
lineChannelId: { required },
|
||||
lineChannelSecret: { required },
|
||||
lineChannelToken: { required },
|
||||
},
|
||||
methods: {
|
||||
async createChannel() {
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const lineChannel = await this.$store.dispatch('inboxes/createChannel', {
|
||||
name: this.channelName,
|
||||
channel: {
|
||||
type: 'line',
|
||||
line_channel_id: this.lineChannelId,
|
||||
line_channel_secret: this.lineChannelSecret,
|
||||
line_channel_token: this.lineChannelToken,
|
||||
},
|
||||
});
|
||||
|
||||
router.replace({
|
||||
name: 'settings_inboxes_add_agents',
|
||||
params: {
|
||||
page: 'new',
|
||||
inbox_id: lineChannel.id,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.ADD.LINE_CHANNEL.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -3,9 +3,6 @@ export default {
|
||||
hostURL() {
|
||||
return window.chatwootConfig.hostURL;
|
||||
},
|
||||
twilioCallbackURL() {
|
||||
return `${this.hostURL}/twilio/callback`;
|
||||
},
|
||||
vapidPublicKey() {
|
||||
return window.chatwootConfig.vapidPublicKey;
|
||||
},
|
||||
|
||||
@@ -11,6 +11,8 @@ class SendReplyJob < ApplicationJob
|
||||
::Twitter::SendOnTwitterService.new(message: message).perform
|
||||
when 'Channel::TwilioSms'
|
||||
::Twilio::SendOnTwilioService.new(message: message).perform
|
||||
when 'Channel::Line'
|
||||
::Line::SendOnLineService.new(message: message).perform
|
||||
when 'Channel::Telegram'
|
||||
::Telegram::SendOnTelegramService.new(message: message).perform
|
||||
end
|
||||
|
||||
24
app/jobs/webhooks/line_events_job.rb
Normal file
24
app/jobs/webhooks/line_events_job.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class Webhooks::LineEventsJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(params: {}, signature: '', post_body: '')
|
||||
@params = params
|
||||
return unless valid_event_payload?
|
||||
return unless valid_post_body?(post_body, signature)
|
||||
|
||||
Line::IncomingMessageService.new(inbox: @channel.inbox, params: @params['line'].with_indifferent_access).perform
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_event_payload?
|
||||
@channel = Channel::Line.find_by(line_channel_id: @params[:line_channel_id]) if @params[:line_channel_id]
|
||||
end
|
||||
|
||||
# https://developers.line.biz/en/reference/messaging-api/#signature-validation
|
||||
# validate the line payload
|
||||
def valid_post_body?(post_body, signature)
|
||||
hash = OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), @channel.line_channel_secret, post_body)
|
||||
Base64.strict_encode64(hash) == signature
|
||||
end
|
||||
end
|
||||
@@ -51,6 +51,7 @@ class Account < ApplicationRecord
|
||||
has_many :web_widgets, dependent: :destroy, class_name: '::Channel::WebWidget'
|
||||
has_many :email_channels, dependent: :destroy, class_name: '::Channel::Email'
|
||||
has_many :api_channels, dependent: :destroy, class_name: '::Channel::Api'
|
||||
has_many :line_channels, dependent: :destroy, class_name: '::Channel::Line'
|
||||
has_many :telegram_channels, dependent: :destroy, class_name: '::Channel::Telegram'
|
||||
has_many :canned_responses, dependent: :destroy
|
||||
has_many :webhooks, dependent: :destroy
|
||||
|
||||
@@ -18,22 +18,15 @@
|
||||
#
|
||||
|
||||
class Channel::Api < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_api'
|
||||
EDITABLE_ATTRS = [:webhook_url].freeze
|
||||
|
||||
validates :account_id, presence: true
|
||||
belongs_to :account
|
||||
|
||||
has_secure_token :identifier
|
||||
has_secure_token :hmac_token
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
|
||||
def name
|
||||
'API'
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,25 +16,20 @@
|
||||
#
|
||||
|
||||
class Channel::Email < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_email'
|
||||
EDITABLE_ATTRS = [:email].freeze
|
||||
|
||||
validates :account_id, presence: true
|
||||
belongs_to :account
|
||||
validates :email, uniqueness: true
|
||||
validates :forward_to_email, uniqueness: true
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
before_validation :ensure_forward_to_email, on: :create
|
||||
|
||||
def name
|
||||
'Email'
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_forward_to_email
|
||||
|
||||
@@ -17,15 +17,12 @@
|
||||
#
|
||||
|
||||
class Channel::FacebookPage < ApplicationRecord
|
||||
self.table_name = 'channel_facebook_pages'
|
||||
|
||||
include Channelable
|
||||
include Reauthorizable
|
||||
|
||||
validates :account_id, presence: true
|
||||
validates :page_id, uniqueness: { scope: :account_id }
|
||||
belongs_to :account
|
||||
self.table_name = 'channel_facebook_pages'
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
validates :page_id, uniqueness: { scope: :account_id }
|
||||
|
||||
after_create_commit :subscribe
|
||||
before_destroy :unsubscribe
|
||||
|
||||
39
app/models/channel/line.rb
Normal file
39
app/models/channel/line.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: channel_line
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# line_channel_secret :string not null
|
||||
# line_channel_token :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :integer not null
|
||||
# line_channel_id :string not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_channel_line_on_line_channel_id (line_channel_id) UNIQUE
|
||||
#
|
||||
|
||||
class Channel::Line < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_line'
|
||||
EDITABLE_ATTRS = [:line_channel_id, :line_channel_secret, :line_channel_token].freeze
|
||||
|
||||
validates :line_channel_id, uniqueness: true, presence: true
|
||||
validates :line_channel_secret, presence: true
|
||||
validates :line_channel_token, presence: true
|
||||
|
||||
def name
|
||||
'LINE'
|
||||
end
|
||||
|
||||
def client
|
||||
@client ||= Line::Bot::Client.new do |config|
|
||||
config.channel_id = line_channel_id
|
||||
config.channel_secret = line_channel_secret
|
||||
config.channel_token = line_channel_token
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -15,14 +15,12 @@
|
||||
#
|
||||
|
||||
class Channel::Telegram < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_telegram'
|
||||
EDITABLE_ATTRS = [:bot_token].freeze
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
belongs_to :account
|
||||
|
||||
before_validation :ensure_valid_bot_token, on: :create
|
||||
validates :account_id, presence: true
|
||||
validates :bot_token, presence: true, uniqueness: true
|
||||
before_save :setup_telegram_webhook
|
||||
|
||||
@@ -30,10 +28,6 @@ class Channel::Telegram < ApplicationRecord
|
||||
'Telegram'
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
|
||||
def telegram_api_url
|
||||
"https://api.telegram.org/bot#{bot_token}"
|
||||
end
|
||||
|
||||
@@ -17,19 +17,16 @@
|
||||
#
|
||||
|
||||
class Channel::TwilioSms < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_twilio_sms'
|
||||
|
||||
validates :account_id, presence: true
|
||||
validates :account_sid, presence: true
|
||||
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
|
||||
|
||||
def name
|
||||
medium == 'sms' ? 'Twilio SMS' : 'Whatsapp'
|
||||
end
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
#
|
||||
|
||||
class Channel::TwitterProfile < ApplicationRecord
|
||||
include Channelable
|
||||
|
||||
self.table_name = 'channel_twitter_profiles'
|
||||
|
||||
validates :account_id, presence: true
|
||||
validates :profile_id, uniqueness: { scope: :account_id }
|
||||
belongs_to :account
|
||||
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
|
||||
before_destroy :unsubscribe
|
||||
|
||||
@@ -30,10 +28,6 @@ class Channel::TwitterProfile < ApplicationRecord
|
||||
'Twitter'
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
|
||||
def create_contact_inbox(profile_id, name, additional_attributes)
|
||||
ActiveRecord::Base.transaction do
|
||||
contact = inbox.account.contacts.create!(additional_attributes: additional_attributes, name: name)
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
#
|
||||
|
||||
class Channel::WebWidget < ApplicationRecord
|
||||
include Channelable
|
||||
include FlagShihTzu
|
||||
|
||||
self.table_name = 'channel_web_widgets'
|
||||
EDITABLE_ATTRS = [:website_url, :widget_color, :welcome_title, :welcome_tagline, :reply_time, :pre_chat_form_enabled,
|
||||
{ pre_chat_form_options: [:pre_chat_message, :require_email] },
|
||||
@@ -34,8 +36,6 @@ class Channel::WebWidget < ApplicationRecord
|
||||
validates :website_url, presence: true
|
||||
validates :widget_color, presence: true
|
||||
|
||||
belongs_to :account
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
has_secure_token :website_token
|
||||
has_secure_token :hmac_token
|
||||
|
||||
@@ -50,10 +50,6 @@ class Channel::WebWidget < ApplicationRecord
|
||||
'Website'
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
|
||||
def web_widget_script
|
||||
"
|
||||
<script>
|
||||
|
||||
12
app/models/concerns/channelable.rb
Normal file
12
app/models/concerns/channelable.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
module Channelable
|
||||
extend ActiveSupport::Concern
|
||||
included do
|
||||
validates :account_id, presence: true
|
||||
belongs_to :account
|
||||
has_one :inbox, as: :channel, dependent: :destroy
|
||||
end
|
||||
|
||||
def has_24_hour_messaging_window?
|
||||
false
|
||||
end
|
||||
end
|
||||
@@ -93,6 +93,15 @@ class Inbox < ApplicationRecord
|
||||
}
|
||||
end
|
||||
|
||||
def webhook_url
|
||||
case channel_type
|
||||
when 'Channel::TwilioSMS'
|
||||
"#{ENV['FRONTEND_URL']}/twilio/callback"
|
||||
when 'Channel::Line'
|
||||
"#{ENV['FRONTEND_URL']}/webhooks/line/#{channel.line_channel_id}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delete_round_robin_agents
|
||||
|
||||
65
app/services/line/incoming_message_service.rb
Normal file
65
app/services/line/incoming_message_service.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
class Line::IncomingMessageService
|
||||
include ::FileTypeHelper
|
||||
pattr_initialize [:inbox!, :params!]
|
||||
|
||||
def perform
|
||||
line_contact_info
|
||||
set_contact
|
||||
set_conversation
|
||||
# TODO: iterate over the events and handle the attachments in future
|
||||
# https://github.com/line/line-bot-sdk-ruby#synopsis
|
||||
@message = @conversation.messages.create(
|
||||
content: params[:events].first['message']['text'],
|
||||
account_id: @inbox.account_id,
|
||||
inbox_id: @inbox.id,
|
||||
message_type: :incoming,
|
||||
sender: @contact,
|
||||
source_id: (params[:events].first['message']['id']).to_s
|
||||
)
|
||||
@message.save!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def account
|
||||
@account ||= inbox.account
|
||||
end
|
||||
|
||||
def line_contact_info
|
||||
@line_contact_info ||= JSON.parse(inbox.channel.client.get_profile(params[:events].first['source']['userId']).body)
|
||||
end
|
||||
|
||||
def set_contact
|
||||
contact_inbox = ::ContactBuilder.new(
|
||||
source_id: line_contact_info['userId'],
|
||||
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
|
||||
}
|
||||
end
|
||||
|
||||
def set_conversation
|
||||
@conversation = @contact_inbox.conversations.first
|
||||
return if @conversation
|
||||
|
||||
@conversation = ::Conversation.create!(conversation_params)
|
||||
end
|
||||
|
||||
def contact_attributes
|
||||
{
|
||||
name: line_contact_info['displayName'],
|
||||
avatar_url: line_contact_info['pictureUrl']
|
||||
}
|
||||
end
|
||||
end
|
||||
11
app/services/line/send_on_line_service.rb
Normal file
11
app/services/line/send_on_line_service.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class Line::SendOnLineService < Base::SendOnChannelService
|
||||
private
|
||||
|
||||
def channel_class
|
||||
Channel::Line
|
||||
end
|
||||
|
||||
def perform_reply
|
||||
channel.client.push_message(message.conversation.contact_inbox.source_id, [{ type: 'text', text: message.content }])
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,7 @@ json.out_of_office_message resource.out_of_office_message
|
||||
json.csat_survey_enabled resource.csat_survey_enabled
|
||||
json.working_hours resource.weekly_schedule
|
||||
json.timezone resource.timezone
|
||||
json.webhook_url resource.webhook_url
|
||||
json.avatar_url resource.try(:avatar_url)
|
||||
json.page_id resource.channel.try(:page_id)
|
||||
json.widget_color resource.channel.try(:widget_color)
|
||||
|
||||
Reference in New Issue
Block a user