123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
- class Chat < ApplicationModel
- validates :name, presence: true
- store :preferences
- def customer_state(session_id = nil)
- return { state: 'chat_disabled' } if !Setting.get('chat')
- # reconnect
- if session_id
- chat_session = Chat::Session.find_by(session_id: session_id, state: %w[waiting running])
- if chat_session
- if chat_session.state == 'running'
- user = nil
- if chat_session.user_id
- chat_user = User.lookup(id: chat_session.user_id)
- url = nil
- if chat_user.image && chat_user.image != 'none'
- url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/users/image/#{chat_user.image}"
- end
- user = {
- name: chat_user.fullname,
- avatar: url,
- }
- # get queue postion if needed
- session = Chat::Session.messages_by_session_id(session_id)
- if session
- return {
- state: 'reconnect',
- session: session,
- agent: user,
- }
- end
- end
- elsif chat_session.state == 'waiting'
- return {
- state: 'reconnect',
- position: chat_session.position,
- }
- end
- end
- end
- # check if agents are available
- available_agents = Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - 2.minutes).count
- if available_agents.zero?
- return { state: 'offline' }
- end
- # if all seads are used
- if Chat.waiting_chat_count >= max_queue
- return {
- state: 'no_seats_available',
- queue: Chat.waiting_chat_count,
- }
- end
- # seads are available
- { state: 'online' }
- end
- def self.agent_state(user_id)
- return { state: 'chat_disabled' } if !Setting.get('chat')
- assets = {}
- Chat.where(active: true).each do |chat|
- assets = chat.assets(assets)
- end
- active_agent_ids = []
- active_agents.each do |user|
- active_agent_ids.push user.id
- assets = user.assets(assets)
- end
- runningchat_session_list_local = running_chat_session_list
- runningchat_session_list_local.each do |session|
- next if !session['user_id']
- user = User.lookup(id: session['user_id'])
- next if !user
- assets = user.assets(assets)
- end
- {
- waiting_chat_count: waiting_chat_count,
- waiting_chat_session_list: waiting_chat_session_list,
- running_chat_count: running_chat_count,
- running_chat_session_list: runningchat_session_list_local,
- active_agent_count: active_agent_count,
- active_agent_ids: active_agent_ids,
- 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)
- return { state: 'chat_disabled' } if !Setting.get('chat')
- result = agent_state(user_id)
- result[:active_sessions] = Chat::Session.active_chats_by_user_id(user_id)
- result
- end
- def self.waiting_chat_count
- Chat::Session.where(state: ['waiting']).count
- end
- def self.waiting_chat_session_list
- sessions = []
- Chat::Session.where(state: ['waiting']).each do |session|
- sessions.push session.attributes
- end
- sessions
- end
- def self.running_chat_count
- Chat::Session.where(state: ['running']).count
- end
- def self.running_chat_session_list
- sessions = []
- Chat::Session.where(state: ['running']).each do |session|
- sessions.push session.attributes
- end
- sessions
- end
- def self.active_chat_count
- Chat::Session.where(state: %w[waiting running]).count
- end
- def self.available_agents(diff = 2.minutes)
- agents = {}
- Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
- agents[record.updated_by_id] = record.concurrent
- end
- agents
- end
- def self.active_agent_count(diff = 2.minutes)
- Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).count
- end
- def self.active_agents(diff = 2.minutes)
- users = []
- Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
- user = User.lookup(id: record.updated_by_id)
- next if !user
- users.push user
- end
- users
- end
- def self.seads_total(diff = 2.minutes)
- total = 0
- available_agents(diff).each_value do |concurrent|
- total += concurrent
- end
- total
- end
- def self.seads_available(diff = 2.minutes)
- seads_total(diff) - active_chat_count
- end
- =begin
- 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
- Chat::Agent.where('active = ? OR updated_at > ?', true, Time.zone.now - 8.hours).each do |item|
- 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)
- end
- 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
- Chat::Session.where(state: 'waiting').order('created_at ASC').each do |local_chat_session|
- 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)
- end
- end
- =begin
- cleanup old chat messages
- Chat.cleanup
- optional you can put the max oldest chat entries
- Chat.cleanup(3.months)
- =end
- def self.cleanup(diff = 3.months)
- Chat::Session.where(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
- Chat::Message.where(chat_session_id: chat_session.id).delete_all
- chat_session.destroy
- end
- true
- end
- =begin
- close chat sessions where participients are offline
- Chat.cleanup_close
- optional you can put the max oldest chat sessions as argument
- Chat.cleanup_close(5.minutes)
- =end
- def self.cleanup_close(diff = 5.minutes)
- Chat::Session.where.not(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
- next if chat_session.recipients_active?
- 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)
- end
- true
- end
- =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?
- return 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
- end
|