320 lines
7.7 KiB
Ruby
320 lines
7.7 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require 'cdr_signal_api'
|
||
|
|
|
||
|
|
class CdrSignal
|
||
|
|
attr_accessor :client
|
||
|
|
|
||
|
|
#
|
||
|
|
# check token and return bot attributes of token
|
||
|
|
#
|
||
|
|
# bot = CdrSignal.check_token('token')
|
||
|
|
#
|
||
|
|
|
||
|
|
def self.check_token(api_url, token)
|
||
|
|
api = CdrSignalAPI.new(api_url, token)
|
||
|
|
begin
|
||
|
|
bot = api.fetch_self
|
||
|
|
rescue StandardError => e
|
||
|
|
raise "invalid api token: #{e.message}"
|
||
|
|
end
|
||
|
|
bot
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# create or update channel, store bot attributes and verify token
|
||
|
|
#
|
||
|
|
# channel = CdrSignal.create_or_update_channel('token', params)
|
||
|
|
#
|
||
|
|
# returns
|
||
|
|
#
|
||
|
|
# channel # instance of Channel
|
||
|
|
#
|
||
|
|
|
||
|
|
def self.create_or_update_channel(api_url, token, params, channel = nil)
|
||
|
|
# verify token
|
||
|
|
bot = CdrSignal.check_token(api_url, token)
|
||
|
|
|
||
|
|
raise 'Bot already exists!' unless channel && CdrSignal.bot_duplicate?(bot['id'])
|
||
|
|
|
||
|
|
raise 'Group needed!' if params[:group_id].blank?
|
||
|
|
|
||
|
|
group = Group.find_by(id: params[:group_id])
|
||
|
|
raise 'Group invalid!' unless group
|
||
|
|
|
||
|
|
unless channel
|
||
|
|
channel = CdrSignal.bot_by_bot_id(bot['id'])
|
||
|
|
channel ||= Channel.new
|
||
|
|
end
|
||
|
|
channel.area = 'Signal::Account'
|
||
|
|
channel.options = {
|
||
|
|
adapter: 'cdr_signal',
|
||
|
|
bot: {
|
||
|
|
id: bot['id'],
|
||
|
|
number: bot['number']
|
||
|
|
},
|
||
|
|
api_token: token,
|
||
|
|
api_url: api_url,
|
||
|
|
welcome: params[:welcome]
|
||
|
|
}
|
||
|
|
channel.group_id = group.id
|
||
|
|
channel.active = true
|
||
|
|
channel.save!
|
||
|
|
channel
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# check if bot already exists as channel
|
||
|
|
#
|
||
|
|
# success = CdrSignal.bot_duplicate?(bot_id)
|
||
|
|
#
|
||
|
|
# returns
|
||
|
|
#
|
||
|
|
# channel # instance of Channel
|
||
|
|
#
|
||
|
|
|
||
|
|
def self.bot_duplicate?(bot_id, channel_id = nil)
|
||
|
|
Channel.where(area: 'Signal::Account').each do |channel|
|
||
|
|
next unless channel.options
|
||
|
|
next unless channel.options[:bot]
|
||
|
|
next unless channel.options[:bot][:id]
|
||
|
|
next if channel.options[:bot][:id] != bot_id
|
||
|
|
next if channel.id.to_s == channel_id.to_s
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# get channel by bot_id
|
||
|
|
#
|
||
|
|
# channel = CdrSignal.bot_by_bot_id(bot_id)
|
||
|
|
#
|
||
|
|
# returns
|
||
|
|
#
|
||
|
|
# true|false
|
||
|
|
#
|
||
|
|
|
||
|
|
def self.bot_by_bot_token(bot_token)
|
||
|
|
Channel.where(area: 'Signal::Account').each do |channel|
|
||
|
|
next unless channel.options
|
||
|
|
next unless channel.options[:bot_token]
|
||
|
|
return channel if channel.options[:bot_token].to_s == bot_token.to_s
|
||
|
|
end
|
||
|
|
nil
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# date = CdrSignal.timestamp_to_date('1543414973285')
|
||
|
|
#
|
||
|
|
# returns
|
||
|
|
#
|
||
|
|
# 2018-11-28T14:22:53.285Z
|
||
|
|
#
|
||
|
|
|
||
|
|
def self.timestamp_to_date(timestamp_str)
|
||
|
|
Time.at(timestamp_str.to_i).utc.to_datetime
|
||
|
|
end
|
||
|
|
|
||
|
|
def self.message_id(message_raw)
|
||
|
|
format('%<source>s@%<timestamp>s', source: message_raw['source'], timestamp: message_raw['timestamp'])
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# client = CdrSignal.new('token')
|
||
|
|
#
|
||
|
|
|
||
|
|
def initialize(api_url, token)
|
||
|
|
@token = token
|
||
|
|
@api_url = api_url
|
||
|
|
@api = CdrSignalAPI.new(api_url, token)
|
||
|
|
end
|
||
|
|
|
||
|
|
#
|
||
|
|
# client.send_message(chat_id, 'some message')
|
||
|
|
#
|
||
|
|
|
||
|
|
def send_message(recipient, message)
|
||
|
|
return if Rails.env.test?
|
||
|
|
|
||
|
|
@api.send_message(recipient, message)
|
||
|
|
end
|
||
|
|
|
||
|
|
def user(number)
|
||
|
|
{
|
||
|
|
# id: params[:message][:from][:id],
|
||
|
|
id: number,
|
||
|
|
username: number
|
||
|
|
# first_name: params[:message][:from][:first_name],
|
||
|
|
# last_name: params[:message][:from][:last_name]
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
def to_user(message)
|
||
|
|
Rails.logger.debug { 'Create user from message...' }
|
||
|
|
Rails.logger.debug { message.inspect }
|
||
|
|
|
||
|
|
# do message_user lookup
|
||
|
|
message_user = user(message[:source])
|
||
|
|
|
||
|
|
# create or update user
|
||
|
|
login = message_user[:username] || message_user[:id]
|
||
|
|
|
||
|
|
auth = Authorization.find_by(uid: message[:source], provider: 'cdr_signal')
|
||
|
|
|
||
|
|
user_data = {
|
||
|
|
login: login,
|
||
|
|
mobile: message[:source]
|
||
|
|
}
|
||
|
|
|
||
|
|
user = if auth
|
||
|
|
User.find(auth.user_id)
|
||
|
|
else
|
||
|
|
User.where(mobile: message[:source]).order(:updated_at).first
|
||
|
|
end
|
||
|
|
if user
|
||
|
|
user.update!(user_data)
|
||
|
|
else
|
||
|
|
user = User.create!(
|
||
|
|
firstname: message[:source],
|
||
|
|
mobile: message[:source],
|
||
|
|
note: "Signal #{message_user[:username]}",
|
||
|
|
active: true,
|
||
|
|
role_ids: Role.signup_role_ids
|
||
|
|
)
|
||
|
|
end
|
||
|
|
|
||
|
|
# create or update authorization
|
||
|
|
auth_data = {
|
||
|
|
uid: message_user[:id],
|
||
|
|
username: login,
|
||
|
|
user_id: user.id,
|
||
|
|
provider: 'cdr_signal'
|
||
|
|
}
|
||
|
|
if auth
|
||
|
|
auth.update!(auth_data)
|
||
|
|
else
|
||
|
|
Authorization.create(auth_data)
|
||
|
|
end
|
||
|
|
|
||
|
|
user
|
||
|
|
end
|
||
|
|
|
||
|
|
def to_ticket(message, user, group_id, channel)
|
||
|
|
UserInfo.current_user_id = user.id
|
||
|
|
|
||
|
|
Rails.logger.debug { 'Create ticket from message...' }
|
||
|
|
Rails.logger.debug { message.inspect }
|
||
|
|
Rails.logger.debug { user.inspect }
|
||
|
|
Rails.logger.debug { group_id.inspect }
|
||
|
|
|
||
|
|
# prepare title
|
||
|
|
title = '-'
|
||
|
|
title = message[:message][:body] unless message[:message][:body].nil?
|
||
|
|
title = "#{title[0, 60]}..." if title.length > 60
|
||
|
|
|
||
|
|
# find ticket or create one
|
||
|
|
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
||
|
|
ticket = Ticket.where(customer_id: user.id).where.not(state_id: state_ids).order(:updated_at).first
|
||
|
|
if ticket
|
||
|
|
|
||
|
|
# check if title need to be updated
|
||
|
|
ticket.title = title if ticket.title == '-'
|
||
|
|
new_state = Ticket::State.find_by(default_create: true)
|
||
|
|
ticket.state = Ticket::State.find_by(default_follow_up: true) if ticket.state_id != new_state.id
|
||
|
|
ticket.save!
|
||
|
|
return ticket
|
||
|
|
end
|
||
|
|
|
||
|
|
ticket = Ticket.new(
|
||
|
|
group_id: group_id,
|
||
|
|
title: title,
|
||
|
|
state_id: Ticket::State.find_by(default_create: true).id,
|
||
|
|
priority_id: Ticket::Priority.find_by(default_create: true).id,
|
||
|
|
customer_id: user.id,
|
||
|
|
preferences: {
|
||
|
|
channel_id: channel.id,
|
||
|
|
cdr_signal: {
|
||
|
|
bot_token: channel.options[:bot_token],
|
||
|
|
chat_id: message[:source]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
)
|
||
|
|
ticket.save!
|
||
|
|
ticket
|
||
|
|
end
|
||
|
|
|
||
|
|
def to_article(message, user, ticket, channel)
|
||
|
|
Rails.logger.debug { 'Create article from message...' }
|
||
|
|
Rails.logger.debug { message.inspect }
|
||
|
|
Rails.logger.debug { user.inspect }
|
||
|
|
Rails.logger.debug { ticket.inspect }
|
||
|
|
|
||
|
|
UserInfo.current_user_id = user.id
|
||
|
|
|
||
|
|
article = Ticket::Article.new(
|
||
|
|
from: message[:source],
|
||
|
|
to: channel[:options][:bot][:number],
|
||
|
|
body: message[:message][:body],
|
||
|
|
content_type: 'text/plain',
|
||
|
|
message_id: "cdr_signal.#{message[:id]}",
|
||
|
|
ticket_id: ticket.id,
|
||
|
|
type_id: Ticket::Article::Type.find_by(name: 'cdr_signal').id,
|
||
|
|
sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
|
||
|
|
internal: false,
|
||
|
|
preferences: {
|
||
|
|
cdr_signal: {
|
||
|
|
timestamp: message[:timestamp],
|
||
|
|
message_id: message[:id],
|
||
|
|
from: message[:source]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
# TODO: attachments
|
||
|
|
# TODO voice
|
||
|
|
# TODO emojis
|
||
|
|
#
|
||
|
|
if message[:message][:body]
|
||
|
|
Rails.logger.debug { article.inspect }
|
||
|
|
article.save!
|
||
|
|
|
||
|
|
Store.remove(
|
||
|
|
object: 'Ticket::Article',
|
||
|
|
o_id: article.id
|
||
|
|
)
|
||
|
|
|
||
|
|
return article
|
||
|
|
end
|
||
|
|
raise 'invalid action'
|
||
|
|
end
|
||
|
|
|
||
|
|
def to_group(message, group_id, channel)
|
||
|
|
# begin import
|
||
|
|
Rails.logger.debug { 'signal import message' }
|
||
|
|
|
||
|
|
# TODO: handle messages in group chats
|
||
|
|
|
||
|
|
return if Ticket::Article.find_by(message_id: message[:id])
|
||
|
|
|
||
|
|
ticket = nil
|
||
|
|
# use transaction
|
||
|
|
Transaction.execute(reset_user_id: true) do
|
||
|
|
user = to_user(message)
|
||
|
|
ticket = to_ticket(message, user, group_id, channel)
|
||
|
|
to_article(message, user, ticket, channel)
|
||
|
|
end
|
||
|
|
|
||
|
|
ticket
|
||
|
|
end
|
||
|
|
|
||
|
|
def from_article(article)
|
||
|
|
# sends a message from a zammad article
|
||
|
|
|
||
|
|
Rails.logger.debug { "Create signal message from article to '#{article[:to]}'..." }
|
||
|
|
|
||
|
|
@api.send_message(article[:to], article[:body])
|
||
|
|
end
|
||
|
|
end
|