123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- class Chat < ApplicationModel
- include ChecksHtmlSanitized
- has_many :sessions, dependent: :destroy
- validates :name, presence: true, uniqueness: { case_sensitive: false }
- store :preferences
- validates :note, length: { maximum: 250 }
- sanitized_html :note
- def customer_state(session_id = nil)
- return { state: 'chat_disabled' } if !Setting.get('chat')
-
- if session_id
- chat_session = Chat::Session.find_by(session_id: session_id, state: %w[waiting running])
- if chat_session
- case chat_session.state
- when 'running'
- user = chat_session.agent_user
- if user
-
- session = Chat::Session.messages_by_session_id(session_id)
- if session
- return {
- state: 'reconnect',
- session: session,
- agent: user,
- }
- end
- end
- when 'waiting'
- return {
- state: 'reconnect',
- position: chat_session.position,
- }
- end
- end
- end
-
- if Chat.active_agent_count([id]).zero?
- return { state: 'offline' }
- end
-
- waiting_count = Chat.waiting_chat_count(id)
- if waiting_count >= max_queue
- return {
- state: 'no_seats_available',
- queue: waiting_count,
- }
- end
-
- { state: 'online' }
- end
- def self.agent_active_chat_ids(user)
- return [] if user.preferences[:chat].blank?
- return [] if user.preferences[:chat][:active].blank?
- chat_ids = []
- user.preferences[:chat][:active].each do |chat_id, state|
- next if state != 'on'
- chat_ids.push chat_id.to_i
- end
- return [] if chat_ids.blank?
- chat_ids
- end
- def self.agent_state(user_id)
- return { state: 'chat_disabled' } if !Setting.get('chat')
- current_user = User.lookup(id: user_id)
- return { error: "No such user with id: #{user_id}" } if !current_user
- chat_ids = agent_active_chat_ids(current_user)
- assets = {}
- Chat.where(active: true).each do |chat|
- assets = chat.assets(assets)
- end
- active_agent_ids = []
- active_agents(chat_ids).each do |user|
- active_agent_ids.push user.id
- assets = user.assets(assets)
- end
- running_chat_session_list_local = running_chat_session_list(chat_ids)
- running_chat_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(chat_ids),
- waiting_chat_count_by_chat: waiting_chat_count_by_chat(chat_ids),
- waiting_chat_session_list: waiting_chat_session_list(chat_ids),
- waiting_chat_session_list_by_chat: waiting_chat_session_list_by_chat(chat_ids),
- running_chat_count: running_chat_count(chat_ids),
- running_chat_session_list: running_chat_session_list_local,
- active_agent_count: active_agent_count(chat_ids),
- active_agent_ids: active_agent_ids,
- seads_available: seads_available(chat_ids),
- seads_total: seads_total(chat_ids),
- active: Chat::Agent.state(user_id),
- assets: assets,
- }
- end
- def self.agent_active_chat?(user, chat_ids)
- return true if user.preferences[:chat].blank?
- return true if user.preferences[:chat][:active].blank?
- chat_ids.each do |chat_id|
- return true if user.preferences[:chat][:active][chat_id] == 'on' || user.preferences[:chat][:active][chat_id.to_s] == 'on'
- end
- false
- 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_ids)
- Chat::Session.where(state: ['waiting'], chat_id: chat_ids).count
- end
- def self.waiting_chat_count_by_chat(chat_ids)
- where(active: true, id: chat_ids)
- .pluck(:id)
- .index_with { |chat_id| waiting_chat_count(chat_id) }
- end
- def self.waiting_chat_session_list(chat_ids)
- Chat::Session
- .where(state: ['waiting'], chat_id: chat_ids)
- .map(&:attributes)
- end
- def self.waiting_chat_session_list_by_chat(chat_ids)
- active_chats = Chat.where(active: true, id: chat_ids).pluck(:id)
- Chat::Session
- .where(chat_id: active_chats, state: ['waiting'])
- .group_by(&:chat_id)
- end
- def self.running_chat_count(chat_ids)
- Chat::Session
- .where(state: ['running'], chat_id: chat_ids)
- .count
- end
- def self.running_chat_session_list(chat_ids)
- Chat::Session
- .where(state: ['running'], chat_id: chat_ids)
- .map(&:attributes)
- end
- def self.active_chat_count(chat_ids)
- Chat::Session.where(state: %w[waiting running], chat_id: chat_ids).count
- end
- def self.available_agents_with_concurrent(chat_ids, diff = 2.minutes)
- agents = {}
- 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
- next if !agent_active_chat?(user, chat_ids)
- agents[record.updated_by_id] = record.concurrent
- end
- agents
- end
- def self.active_agent_count(chat_ids, diff = 2.minutes)
- count = 0
- 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
- next if !agent_active_chat?(user, chat_ids)
- count += 1
- end
- count
- end
- def self.active_agents(chat_ids, 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
- next if !agent_active_chat?(user, chat_ids)
- users.push user
- end
- users
- end
- def self.seads_total(chat_ids, diff = 2.minutes)
- total = 0
- available_agents_with_concurrent(chat_ids, diff).each_value do |concurrent|
- total += concurrent
- end
- total
- end
- def self.seads_available(chat_ids, diff = 2.minutes)
- seads_total(chat_ids, diff) - active_chat_count(chat_ids)
- end
- def self.broadcast_agent_state_update(chat_ids, ignore_user_id = nil)
-
- Chat::Agent.where('active = ? OR updated_at > ?', true, 8.hours.ago).each do |item|
- next if item.updated_by_id == ignore_user_id
- user = User.lookup(id: item.updated_by_id)
- next if !user
- next if !agent_active_chat?(user, chat_ids)
- data = {
- event: 'chat_status_agent',
- data: Chat.agent_state(item.updated_by_id),
- }
- Sessions.send_to(item.updated_by_id, data)
- end
- end
- def self.broadcast_customer_state_update(chat_id)
-
- position = 0
- Chat::Session.where(state: 'waiting', chat_id: chat_id).reorder(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
- def self.cleanup(diff = 12.months)
- Chat::Session
- .where(state: 'closed', updated_at: ...diff.ago)
- .each(&:destroy)
- true
- end
- def self.cleanup_close(diff = 5.minutes)
- Chat::Session
- .where.not(state: 'closed')
- .where(updated_at: ...diff.ago)
- .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
- 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?(%r{#{local_ip.strip.gsub(%r{\*}, '.+?')}})
- end
- false
- end
- def website_allowed?(website)
- return true if allowed_websites.blank?
- allowed_websites.split(';').any? do |allowed_website|
- website.downcase.include?(allowed_website.downcase.strip)
- end
- 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.any?(geo_ip['country_code'])
- end
- end
|