link-stack/packages/zammad-addon-metamigo/src/lib/cdr_whatsapp.rb

320 lines
7.7 KiB
Ruby
Raw Normal View History

2023-02-13 12:41:30 +00:00
# frozen_string_literal: true
require 'cdr_whatsapp_api'
class CdrWhatsapp
attr_accessor :client
#
# check token and return bot attributes of token
#
# bot = CdrWhatsapp.check_token('token')
#
def self.check_token(api_url, token)
api = CdrWhatsappAPI.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 = CdrWhatsapp.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 = CdrWhatsapp.check_token(api_url, token)
raise 'Bot already exists!' unless channel && CdrWhatsapp.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 = CdrWhatsapp.bot_by_bot_id(bot['id'])
channel ||= Channel.new
end
channel.area = 'Whatsapp::Account'
channel.options = {
adapter: 'cdr_whatsapp',
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 = CdrWhatsapp.bot_duplicate?(bot_id)
#
# returns
#
# channel # instance of Channel
#
def self.bot_duplicate?(bot_id, channel_id = nil)
Channel.where(area: 'Whatsapp::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 = CdrWhatsapp.bot_by_bot_id(bot_id)
#
# returns
#
# true|false
#
def self.bot_by_bot_token(bot_token)
Channel.where(area: 'Whatsapp::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 = CdrWhatsapp.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 = CdrWhatsapp.new('token')
#
def initialize(api_url, token)
@token = token
@api_url = api_url
@api = CdrWhatsappAPI.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: 'whatsapp')
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: "Whatsapp #{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_whatsapp'
}
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_whatsapp: {
bot_id: channel.options[:bot][:id],
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_whatsapp.#{message[:id]}",
ticket_id: ticket.id,
type_id: Ticket::Article::Type.find_by(name: 'cdr_whatsapp').id,
sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
internal: false,
preferences: {
cdr_whatsapp: {
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 { 'whatsapp 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 whatsapp message from article to '#{article[:to]}'..." }
@api.send_message(article[:to], article[:body])
end
end