2016-10-19 03:11:36 +00:00
|
|
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
2015-11-10 14:01:04 +00:00
|
|
|
|
|
|
|
class Chat < ApplicationModel
|
2015-11-16 10:44:13 +00:00
|
|
|
validates :name, presence: true
|
2015-11-17 15:39:46 +00:00
|
|
|
store :preferences
|
2015-11-10 14:01:04 +00:00
|
|
|
|
2015-11-12 09:39:14 +00:00
|
|
|
def customer_state(session_id = nil)
|
2015-11-26 10:12:01 +00:00
|
|
|
return { state: 'chat_disabled' } if !Setting.get('chat')
|
2015-11-10 14:01:04 +00:00
|
|
|
|
2015-11-12 22:58:35 +00:00
|
|
|
# reconnect
|
2015-11-12 09:39:14 +00:00
|
|
|
if session_id
|
2017-11-23 08:09:44 +00:00
|
|
|
chat_session = Chat::Session.find_by(session_id: session_id, state: %w[waiting running])
|
2015-11-12 15:16:01 +00:00
|
|
|
|
2015-11-12 22:58:35 +00:00
|
|
|
if chat_session
|
2015-11-13 14:15:44 +00:00
|
|
|
if chat_session.state == 'running'
|
|
|
|
user = nil
|
|
|
|
if chat_session.user_id
|
2015-11-30 10:50:02 +00:00
|
|
|
chat_user = User.lookup(id: chat_session.user_id)
|
2015-11-13 14:15:44 +00:00
|
|
|
url = nil
|
|
|
|
if chat_user.image && chat_user.image != 'none'
|
2015-11-25 12:24:17 +00:00
|
|
|
url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/users/image/#{chat_user.image}"
|
2015-11-13 14:15:44 +00:00
|
|
|
end
|
|
|
|
user = {
|
|
|
|
name: chat_user.fullname,
|
|
|
|
avatar: url,
|
|
|
|
}
|
|
|
|
|
|
|
|
# get queue postion if needed
|
2015-11-13 16:03:58 +00:00
|
|
|
session = Chat::Session.messages_by_session_id(session_id)
|
2015-11-13 14:15:44 +00:00
|
|
|
if session
|
|
|
|
return {
|
|
|
|
state: 'reconnect',
|
|
|
|
session: session,
|
|
|
|
agent: user,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elsif chat_session.state == 'waiting'
|
2015-11-12 22:58:35 +00:00
|
|
|
return {
|
|
|
|
state: 'reconnect',
|
2015-11-13 14:15:44 +00:00
|
|
|
position: chat_session.position,
|
2015-11-12 22:58:35 +00:00
|
|
|
}
|
|
|
|
end
|
2015-11-12 15:16:01 +00:00
|
|
|
end
|
2015-11-12 09:39:14 +00:00
|
|
|
end
|
|
|
|
|
2015-11-13 14:15:44 +00:00
|
|
|
# check if agents are available
|
|
|
|
available_agents = Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - 2.minutes).count
|
2016-01-16 10:05:04 +00:00
|
|
|
if available_agents.zero?
|
2015-11-13 14:15:44 +00:00
|
|
|
return { state: 'offline' }
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|
|
|
|
|
2015-11-13 14:15:44 +00:00
|
|
|
# if all seads are used
|
2015-11-25 09:33:39 +00:00
|
|
|
if Chat.waiting_chat_count >= max_queue
|
2015-11-13 14:15:44 +00:00
|
|
|
return {
|
|
|
|
state: 'no_seats_available',
|
2015-11-25 09:33:39 +00:00
|
|
|
queue: Chat.waiting_chat_count,
|
2015-11-13 14:15:44 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
# seads are available
|
|
|
|
{ state: 'online' }
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.agent_state(user_id)
|
2016-01-05 13:47:41 +00:00
|
|
|
return { state: 'chat_disabled' } if !Setting.get('chat')
|
|
|
|
assets = {}
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat.where(active: true).each do |chat|
|
2016-01-05 13:47:41 +00:00
|
|
|
assets = chat.assets(assets)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 21:15:19 +00:00
|
|
|
active_agent_ids = []
|
2017-10-01 12:25:52 +00:00
|
|
|
active_agents.each do |user|
|
2016-01-05 21:15:19 +00:00
|
|
|
active_agent_ids.push user.id
|
|
|
|
assets = user.assets(assets)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 21:15:19 +00:00
|
|
|
runningchat_session_list_local = running_chat_session_list
|
2017-10-01 12:25:52 +00:00
|
|
|
runningchat_session_list_local.each do |session|
|
2016-01-05 21:15:19 +00:00
|
|
|
next if !session['user_id']
|
|
|
|
user = User.lookup(id: session['user_id'])
|
|
|
|
next if !user
|
|
|
|
assets = user.assets(assets)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 13:47:41 +00:00
|
|
|
{
|
|
|
|
waiting_chat_count: waiting_chat_count,
|
2016-01-05 21:15:19 +00:00
|
|
|
waiting_chat_session_list: waiting_chat_session_list,
|
2016-01-05 13:47:41 +00:00
|
|
|
running_chat_count: running_chat_count,
|
2016-01-05 21:15:19 +00:00
|
|
|
running_chat_session_list: runningchat_session_list_local,
|
|
|
|
active_agent_count: active_agent_count,
|
|
|
|
active_agent_ids: active_agent_ids,
|
2016-01-05 13:47:41 +00:00
|
|
|
seads_available: seads_available,
|
|
|
|
seads_total: seads_total,
|
|
|
|
active: Chat::Agent.state(user_id),
|
|
|
|
assets: assets,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.agent_state_with_sessions(user_id)
|
2015-11-26 10:12:01 +00:00
|
|
|
return { state: 'chat_disabled' } if !Setting.get('chat')
|
2016-01-05 21:15:19 +00:00
|
|
|
result = agent_state(user_id)
|
|
|
|
result[:active_sessions] = Chat::Session.active_chats_by_user_id(user_id)
|
|
|
|
result
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.waiting_chat_count
|
|
|
|
Chat::Session.where(state: ['waiting']).count
|
|
|
|
end
|
|
|
|
|
2016-01-05 21:15:19 +00:00
|
|
|
def self.waiting_chat_session_list
|
|
|
|
sessions = []
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Session.where(state: ['waiting']).each do |session|
|
2016-01-05 21:15:19 +00:00
|
|
|
sessions.push session.attributes
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 21:15:19 +00:00
|
|
|
sessions
|
|
|
|
end
|
|
|
|
|
2015-11-10 14:01:04 +00:00
|
|
|
def self.running_chat_count
|
2015-11-11 20:44:54 +00:00
|
|
|
Chat::Session.where(state: ['running']).count
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|
|
|
|
|
2016-01-05 21:15:19 +00:00
|
|
|
def self.running_chat_session_list
|
|
|
|
sessions = []
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Session.where(state: ['running']).each do |session|
|
2016-01-05 21:15:19 +00:00
|
|
|
sessions.push session.attributes
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 21:15:19 +00:00
|
|
|
sessions
|
|
|
|
end
|
|
|
|
|
2015-11-13 16:03:58 +00:00
|
|
|
def self.active_chat_count
|
2017-11-23 08:09:44 +00:00
|
|
|
Chat::Session.where(state: %w[waiting running]).count
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|
|
|
|
|
2015-11-13 16:03:58 +00:00
|
|
|
def self.available_agents(diff = 2.minutes)
|
2015-11-10 14:01:04 +00:00
|
|
|
agents = {}
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
|
2015-11-10 14:01:04 +00:00
|
|
|
agents[record.updated_by_id] = record.concurrent
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-11-10 14:01:04 +00:00
|
|
|
agents
|
|
|
|
end
|
|
|
|
|
2016-01-05 21:15:19 +00:00
|
|
|
def self.active_agent_count(diff = 2.minutes)
|
2015-11-16 10:44:13 +00:00
|
|
|
Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).count
|
|
|
|
end
|
|
|
|
|
2016-01-05 21:15:19 +00:00
|
|
|
def self.active_agents(diff = 2.minutes)
|
|
|
|
users = []
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
|
2016-01-05 21:15:19 +00:00
|
|
|
user = User.lookup(id: record.updated_by_id)
|
|
|
|
next if !user
|
|
|
|
users.push user
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-05 21:15:19 +00:00
|
|
|
users
|
|
|
|
end
|
|
|
|
|
2015-11-13 16:03:58 +00:00
|
|
|
def self.seads_total(diff = 2.minutes)
|
2015-11-10 14:01:04 +00:00
|
|
|
total = 0
|
2017-11-23 08:09:44 +00:00
|
|
|
available_agents(diff).each_value do |concurrent|
|
2015-11-10 14:01:04 +00:00
|
|
|
total += concurrent
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-11-10 14:01:04 +00:00
|
|
|
total
|
|
|
|
end
|
|
|
|
|
2015-11-13 16:03:58 +00:00
|
|
|
def self.seads_available(diff = 2.minutes)
|
2015-11-10 14:01:04 +00:00
|
|
|
seads_total(diff) - active_chat_count
|
|
|
|
end
|
2015-12-10 10:35:00 +00:00
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2016-01-06 00:45:03 +00:00
|
|
|
broadcast new agent status to all agents
|
|
|
|
|
|
|
|
Chat.broadcast_agent_state_update
|
|
|
|
|
|
|
|
optional you can ignore it for dedecated user
|
|
|
|
|
|
|
|
Chat.broadcast_agent_state_update(ignore_user_id)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.broadcast_agent_state_update(ignore_user_id = nil)
|
|
|
|
|
|
|
|
# send broadcast to agents
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Agent.where('active = ? OR updated_at > ?', true, Time.zone.now - 8.hours).each do |item|
|
2016-01-06 00:45:03 +00:00
|
|
|
next if item.updated_by_id == ignore_user_id
|
|
|
|
data = {
|
|
|
|
event: 'chat_status_agent',
|
|
|
|
data: Chat.agent_state(item.updated_by_id),
|
|
|
|
}
|
|
|
|
Sessions.send_to(item.updated_by_id, data)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-06 00:45:03 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
broadcast new customer queue position to all waiting customers
|
|
|
|
|
|
|
|
Chat.broadcast_customer_state_update
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.broadcast_customer_state_update
|
|
|
|
|
|
|
|
# send position update to other waiting sessions
|
|
|
|
position = 0
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Session.where(state: 'waiting').order('created_at ASC').each do |local_chat_session|
|
2016-01-06 00:45:03 +00:00
|
|
|
position += 1
|
|
|
|
data = {
|
|
|
|
event: 'chat_session_queue',
|
|
|
|
data: {
|
|
|
|
state: 'queue',
|
|
|
|
position: position,
|
|
|
|
session_id: local_chat_session.session_id,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
local_chat_session.send_to_recipients(data)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2016-01-06 00:45:03 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
2015-12-10 10:35:00 +00:00
|
|
|
cleanup old chat messages
|
|
|
|
|
|
|
|
Chat.cleanup
|
|
|
|
|
2016-08-17 11:24:51 +00:00
|
|
|
optional you can put the max oldest chat entries
|
2015-12-10 10:35:00 +00:00
|
|
|
|
|
|
|
Chat.cleanup(3.months)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.cleanup(diff = 3.months)
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Session.where(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
|
2015-12-10 10:35:00 +00:00
|
|
|
Chat::Message.where(chat_session_id: chat_session.id).delete_all
|
|
|
|
chat_session.destroy
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-12-10 10:35:00 +00:00
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
close chat sessions where participients are offline
|
|
|
|
|
|
|
|
Chat.cleanup_close
|
|
|
|
|
2016-08-17 11:24:51 +00:00
|
|
|
optional you can put the max oldest chat sessions as argument
|
2015-12-10 10:35:00 +00:00
|
|
|
|
|
|
|
Chat.cleanup_close(5.minutes)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.cleanup_close(diff = 5.minutes)
|
2017-10-01 12:25:52 +00:00
|
|
|
Chat::Session.where.not(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
|
2015-12-10 10:37:02 +00:00
|
|
|
next if chat_session.recipients_active?
|
2015-12-10 10:35:00 +00:00
|
|
|
chat_session.state = 'closed'
|
|
|
|
chat_session.save
|
|
|
|
message = {
|
|
|
|
event: 'chat_session_closed',
|
|
|
|
data: {
|
|
|
|
session_id: chat_session.session_id,
|
|
|
|
realname: 'System',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
chat_session.send_to_recipients(message)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-12-10 10:35:00 +00:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2018-01-28 23:52:02 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
check if ip address is blocked for chat
|
|
|
|
|
|
|
|
chat = Chat.find(123)
|
|
|
|
chat.blocked_ip?(ip)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def blocked_ip?(ip)
|
|
|
|
return false if ip.blank?
|
|
|
|
return false if block_ip.blank?
|
|
|
|
ips = block_ip.split(';')
|
|
|
|
ips.each do |local_ip|
|
|
|
|
return true if ip == local_ip.strip
|
|
|
|
return true if ip.match?(/#{local_ip.strip.gsub(/\*/, '.+?')}/)
|
|
|
|
end
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
=begin
|
|
|
|
|
|
|
|
check if country is blocked for chat
|
|
|
|
|
|
|
|
chat = Chat.find(123)
|
|
|
|
chat.blocked_country?(ip)
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def blocked_country?(ip)
|
|
|
|
return false if ip.blank?
|
|
|
|
retunn false if block_country.blank?
|
|
|
|
geo_ip = Service::GeoIp.location(ip)
|
|
|
|
return false if geo_ip.blank?
|
|
|
|
return false if geo_ip['country_code'].blank?
|
|
|
|
countries = block_country.split(';')
|
|
|
|
countries.each do |local_country|
|
|
|
|
return true if geo_ip['country_code'] == local_country
|
|
|
|
end
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2015-11-10 14:01:04 +00:00
|
|
|
end
|