From 8a5552c9f8a5da2ab38c819923d461dfba25e938 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Tue, 12 Nov 2019 17:06:42 +0100 Subject: [PATCH] Fixes issue #2441 - Zammad ignores disabled Chat-Topics for agents. --- .../javascripts/app/controllers/chat.coffee | 4 + app/models/chat.rb | 390 ++++++++++++++++-- .../observer/chat/leave/background_job.rb | 2 +- lib/sessions/event/chat_agent_state.rb | 6 +- lib/sessions/event/chat_session_close.rb | 4 +- lib/sessions/event/chat_session_init.rb | 4 +- lib/sessions/event/chat_session_start.rb | 11 +- test/unit/chat_test.rb | 187 ++++++++- 8 files changed, 544 insertions(+), 64 deletions(-) diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index f677953f8861..c5fca405e8e6 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -832,6 +832,10 @@ class Setting extends App.ControllerModal # update runtime @windowSpace.maxChatWindows = params.chat.max_windows + # disable chat if we have no active chat selected + if params.chat && ( _.isEmpty(params.chat.active) || !_.includes(_.values(params.chat.active), 'on') ) + @active = false + # update user preferences @ajax( id: 'preferences' diff --git a/app/models/chat.rb b/app/models/chat.rb index 88e1a18c3f97..145279937b59 100644 --- a/app/models/chat.rb +++ b/app/models/chat.rb @@ -4,6 +4,60 @@ class Chat < ApplicationModel validates :name, presence: true store :preferences +=begin + +get the customer state of a chat + + chat = Chat.find(123) + chat.customer_state(session_id = nil) + +returns + +chat_disabled - chat is disabled + + { + state: 'chat_disabled' + } + +returns (without session_id) + +offline - no agent is online + + { + state: 'offline' + } + +no_seats_available - no agent is available (all slots are used, max_queue is full) + + { + state: 'no_seats_available' + } + +online - ready for chats + + { + state: 'online' + } + +returns (session_id) + +reconnect - position of waiting list for new chat + + { + state: 'reconnect', + position: chat_session.position, + } + +reconnect - chat session already exists, serve agent and session chat messages (to redraw chat history) + + { + state: 'reconnect', + session: session, + agent: user, + } + +=end + def customer_state(session_id = nil) return { state: 'chat_disabled' } if !Setting.get('chat') @@ -45,16 +99,16 @@ def customer_state(session_id = nil) 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? + if Chat.active_agent_count([id]).zero? return { state: 'offline' } end # if all seads are used - if Chat.waiting_chat_count >= max_queue + waiting_count = Chat.waiting_chat_count(id) + if waiting_count >= max_queue return { state: 'no_seats_available', - queue: Chat.waiting_chat_count, + queue: waiting_count, } end @@ -62,20 +116,101 @@ def customer_state(session_id = nil) { state: 'online' } end +=begin + +get available chat_ids for agent + + chat_ids = Chat.agent_active_chat_ids(User.find(123)) + +returns + + [1, 2, 3] + +=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 + +=begin + +get current agent state + + Chat.agent_state(123) + +returns + + { + state: 'chat_disabled' + } + + { + waiting_chat_count: 1, + waiting_chat_session_list: [ + { + id: 17, + chat_id: 1, + session_id: "81e58184385aabe92508eb9233200b5e", + name: "", + state: "waiting", + user_id: nil, + preferences: { + "url: "http://localhost:3000/chat.html", + "participants: ["70332537618180"], + "remote_ip: nil, + "geo_ip: nil, + "dns_name: nil, + }, + updated_by_id: nil, + created_by_id: nil, + created_at: Thu, 02 May 2019 10:10:45 UTC +00:00, + updated_at: Thu, 02 May 2019 10:10:45 UTC +00:00}, + } + ], + running_chat_count: 0, + running_chat_session_list: [], + active_agent_count: 2, + active_agent_ids: [1, 2], + seads_available: 5, + seads_total: 15, + active: true, # agent is available for chats + assets: { ...related assets... }, + } + +=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.each do |user| + active_agents(chat_ids).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| + + 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']) @@ -83,20 +218,78 @@ def self.agent_state(user_id) 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, + waiting_chat_count: waiting_chat_count(chat_ids), + waiting_chat_session_list: waiting_chat_session_list(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, - seads_total: seads_total, + seads_available: seads_available(chat_ids), + seads_total: seads_total(chat_ids), active: Chat::Agent.state(user_id), assets: assets, } end +=begin + +check if agent is available for chat_ids + + chat_ids = Chat.agent_active_chat?(User.find(123), [1, 2]) + +returns + + true|false + +=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 + +=begin + +list all active sessins by user_id + + Chat.agent_state_with_sessions(123) + +returns + + the same as Chat.agent_state(123) but with the following addition + + active_sessions: [ + { + id: 19, + chat_id: 1, + session_id: "f28b2704e381c668c9b59215e9481310", + name: "", + state: "running", + user_id: 3, + preferences: { + url: "http://localhost/chat.html", + participants: ["70332475730240", "70332481108980"], + remote_ip: nil, + geo_ip: nil, + dns_name: nil + }, + updated_by_id: nil, + created_by_id: nil, + created_at: Thu, 02 May 2019 11:48:25 UTC +00:00, + updated_at: Thu, 02 May 2019 11:48:29 UTC +00:00, + messages: [] + } +] + +=end + def self.agent_state_with_sessions(user_id) return { state: 'chat_disabled' } if !Setting.get('chat') @@ -105,87 +298,204 @@ def self.agent_state_with_sessions(user_id) result end - def self.waiting_chat_count - Chat::Session.where(state: ['waiting']).count +=begin + +get count if waiting sessions in given chats + + Chat.waiting_chat_count(chat_ids) + +returns + + 123 + +=end + + def self.waiting_chat_count(chat_ids) + Chat::Session.where(state: ['waiting'], chat_id: chat_ids).count end - def self.waiting_chat_session_list + def self.waiting_chat_session_list(chat_ids) sessions = [] - Chat::Session.where(state: ['waiting']).each do |session| + Chat::Session.where(state: ['waiting'], chat_id: chat_ids).each do |session| sessions.push session.attributes end sessions end - def self.running_chat_count - Chat::Session.where(state: ['running']).count +=begin + +get count running sessions in given chats + + Chat.running_chat_count(chat_ids) + +returns + + 123 + +=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 + def self.running_chat_session_list(chat_ids) sessions = [] - Chat::Session.where(state: ['running']).each do |session| + Chat::Session.where(state: ['running'], chat_id: chat_ids).each do |session| sessions.push session.attributes end sessions end - def self.active_chat_count - Chat::Session.where(state: %w[waiting running]).count +=begin + +get count of active sessions in given chats + + Chat.active_chat_count(chat_ids) + +returns + + 123 + +=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(diff = 2.minutes) +=begin + +get user agents with concurrent + + Chat.available_agents_with_concurrent(chat_ids) + +returns + + { + 123: 5, + 124: 1, + 125: 2, + } + +=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(diff = 2.minutes) - Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).count +=begin + +get count of active agents in given chats + + Chat.active_agent_count(chat_ids) + +returns + + 123 + +=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(diff = 2.minutes) +=begin + +get active agents in given chats + + Chat.active_agent_count(chat_ids) + +returns + + [User.find(123), User.find(345)] + +=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(diff = 2.minutes) +=begin + +get count all possible seads (possible chat sessions) in given chats + + Chat.seads_total(chat_ids) + +returns + + 123 + +=end + + def self.seads_total(chat_ids, diff = 2.minutes) total = 0 - available_agents(diff).each_value do |concurrent| + available_agents_with_concurrent(chat_ids, diff).each_value do |concurrent| total += concurrent end total end - def self.seads_available(diff = 2.minutes) - seads_total(diff) - active_chat_count +=begin + +get count all available seads (available chat sessions) in given chats + + Chat.seads_available(chat_ids) + +returns + + 123 + +=end + + def self.seads_available(chat_ids, diff = 2.minutes) + seads_total(chat_ids, diff) - active_chat_count(chat_ids) end =begin broadcast new agent status to all agents - Chat.broadcast_agent_state_update + Chat.broadcast_agent_state_update(chat_ids) optional you can ignore it for dedicated user - Chat.broadcast_agent_state_update(ignore_user_id) + Chat.broadcast_agent_state_update(chat_ids, ignore_user_id) =end - def self.broadcast_agent_state_update(ignore_user_id = nil) + def self.broadcast_agent_state_update(chat_ids, 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 + 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), @@ -198,15 +508,15 @@ def self.broadcast_agent_state_update(ignore_user_id = nil) broadcast new customer queue position to all waiting customers - Chat.broadcast_customer_state_update + Chat.broadcast_customer_state_update(chat_id) =end - def self.broadcast_customer_state_update + def self.broadcast_customer_state_update(chat_id) # send position update to other waiting sessions position = 0 - Chat::Session.where(state: 'waiting').order(created_at: :asc).each do |local_chat_session| + Chat::Session.where(state: 'waiting', chat_id: chat_id).order(created_at: :asc).each do |local_chat_session| position += 1 data = { event: 'chat_session_queue', @@ -228,11 +538,11 @@ def self.broadcast_customer_state_update optional you can put the max oldest chat entries - Chat.cleanup(3.months) + Chat.cleanup(12.months) =end - def self.cleanup(diff = 3.months) + def self.cleanup(diff = 12.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 diff --git a/app/models/observer/chat/leave/background_job.rb b/app/models/observer/chat/leave/background_job.rb index 1128f201bb48..d24edde24a73 100644 --- a/app/models/observer/chat/leave/background_job.rb +++ b/app/models/observer/chat/leave/background_job.rb @@ -30,7 +30,7 @@ def perform } chat_session.send_to_recipients(message, @client_id) - Chat.broadcast_agent_state_update + Chat.broadcast_agent_state_update([chat_session.chat_id]) end end diff --git a/lib/sessions/event/chat_agent_state.rb b/lib/sessions/event/chat_agent_state.rb index b6363b5ff183..bf061b0a7f7a 100644 --- a/lib/sessions/event/chat_agent_state.rb +++ b/lib/sessions/event/chat_agent_state.rb @@ -6,10 +6,14 @@ def run # check if user has permissions return if !permission_check('chat.agent', 'chat') + chat_user = User.lookup(id: @session['id']) + Chat::Agent.state(@session['id'], @payload['data']['active']) + chat_ids = Chat.agent_active_chat_ids(chat_user) + # broadcast new state to agents - Chat.broadcast_agent_state_update(@session['id']) + Chat.broadcast_agent_state_update(chat_ids, @session['id']) { event: 'chat_agent_state', diff --git a/lib/sessions/event/chat_session_close.rb b/lib/sessions/event/chat_session_close.rb index ff29a8a6108c..6a1dad8e75f2 100644 --- a/lib/sessions/event/chat_session_close.rb +++ b/lib/sessions/event/chat_session_close.rb @@ -32,10 +32,10 @@ def run chat_session.save # set state update to all agents - Chat.broadcast_agent_state_update + Chat.broadcast_agent_state_update([chat_session.chat_id]) # send position update to other waiting sessions - Chat.broadcast_customer_state_update + Chat.broadcast_customer_state_update(chat_session.chat_id) # notify about "leaving" else diff --git a/lib/sessions/event/chat_session_init.rb b/lib/sessions/event/chat_session_init.rb index d779d2bcf05b..b4fdf8575d97 100644 --- a/lib/sessions/event/chat_session_init.rb +++ b/lib/sessions/event/chat_session_init.rb @@ -40,14 +40,14 @@ def run ) # send broadcast to agents - Chat.broadcast_agent_state_update + Chat.broadcast_agent_state_update([chat_session.chat_id]) # return new session { event: 'chat_session_queue', data: { state: 'queue', - position: Chat.waiting_chat_count, + position: Chat.waiting_chat_count([chat_session.chat_id]), session_id: chat_session.session_id, }, } diff --git a/lib/sessions/event/chat_session_start.rb b/lib/sessions/event/chat_session_start.rb index f38c80c8f398..7a90a7c7dc23 100644 --- a/lib/sessions/event/chat_session_start.rb +++ b/lib/sessions/event/chat_session_start.rb @@ -5,7 +5,9 @@ def run return if !permission_check('chat.agent', 'chat') # find first in waiting list - chat_session = Chat::Session.where(state: 'waiting').order(created_at: :asc).first + chat_user = User.lookup(id: @session['id']) + chat_ids = Chat.agent_active_chat_ids(chat_user) + chat_session = Chat::Session.where(state: 'waiting', chat_id: chat_ids).order(created_at: :asc).first if !chat_session return { event: 'chat_session_start', @@ -15,13 +17,12 @@ def run }, } end - chat_session.user_id = @session['id'] + chat_session.user_id = chat_user.id chat_session.state = 'running' chat_session.preferences[:participants] = chat_session.add_recipient(@client_id) chat_session.save # send chat_session_init to client - 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}" @@ -52,10 +53,10 @@ def run Sessions.send(@client_id, data) # send state update with sessions to agents - Chat.broadcast_agent_state_update + Chat.broadcast_agent_state_update([chat_session.chat_id]) # send position update to other waiting sessions - Chat.broadcast_customer_state_update + Chat.broadcast_customer_state_update(chat_session.chat_id) nil end diff --git a/test/unit/chat_test.rb b/test/unit/chat_test.rb index b9cfbfbd8f9e..1b46f0d40875 100644 --- a/test/unit/chat_test.rb +++ b/test/unit/chat_test.rb @@ -5,7 +5,7 @@ class ChatTest < ActiveSupport::TestCase setup do groups = Group.all roles = Role.where(name: %w[Agent]) - @agent1 = User.create_or_update( + @agent1 = User.create!( login: 'ticket-chat-agent1@example.com', firstname: 'Notification', lastname: 'Agent1', @@ -18,7 +18,7 @@ class ChatTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, ) - @agent2 = User.create_or_update( + @agent2 = User.create!( login: 'ticket-chat-agent2@example.com', firstname: 'Notification', lastname: 'Agent2', @@ -130,8 +130,7 @@ def send(msg) end test 'default test' do - - chat = Chat.create_or_update( + chat = Chat.create!( name: 'default', max_queue: 5, note: '', @@ -140,6 +139,19 @@ def send(msg) created_by_id: 1, ) + @agent1.preferences[:chat] = { + active: { + chat.id => 'on', + }, + } + @agent1.save! + @agent2.preferences[:chat] = { + active: { + chat.id => 'on', + }, + } + @agent2.save! + # check if feature is disabled assert_equal('chat_disabled', chat.customer_state[:state]) assert_equal('chat_disabled', Chat.agent_state(@agent1.id)[:state]) @@ -178,7 +190,7 @@ def send(msg) assert_equal(true, agent_state[:active]) # start session - chat_session1 = Chat::Session.create( + chat_session1 = Chat::Session.create!( chat_id: chat.id, user_id: @agent1.id, ) @@ -197,7 +209,7 @@ def send(msg) assert_equal(true, agent_state[:active]) # activate second agent - chat_agent2 = Chat::Agent.create_or_update( + chat_agent2 = Chat::Agent.create!( active: true, concurrent: 2, updated_by_id: @agent2.id, @@ -255,13 +267,13 @@ def send(msg) Chat::Session.create( chat_id: chat.id, ) - chat_session4 = Chat::Session.create( + chat_session4 = Chat::Session.create!( chat_id: chat.id, ) - chat_session5 = Chat::Session.create( + chat_session5 = Chat::Session.create!( chat_id: chat.id, ) - chat_session6 = Chat::Session.create( + chat_session6 = Chat::Session.create!( chat_id: chat.id, ) @@ -290,25 +302,25 @@ def send(msg) chat_session6.state = 'running' chat_session6.save - Chat::Message.create( + Chat::Message.create!( chat_session_id: chat_session6.id, content: 'message 1', created_by_id: @agent1.id, ) travel 1.second - Chat::Message.create( + Chat::Message.create!( chat_session_id: chat_session6.id, content: 'message 2', created_by_id: @agent1.id, ) travel 1.second - Chat::Message.create( + Chat::Message.create!( chat_session_id: chat_session6.id, content: 'message 3', created_by_id: @agent1.id, ) travel 1.second - Chat::Message.create( + Chat::Message.create!( chat_session_id: chat_session6.id, content: 'message 4', created_by_id: nil, @@ -441,6 +453,155 @@ def send(msg) travel_back end + test 'check if agent_state_with_sessions works correctly with 2 chats' do + chat1 = Chat.create!( + name: 'topic 1', + max_queue: 5, + note: '', + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + chat2 = Chat.create!( + name: 'topic 2', + max_queue: 5, + note: '', + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + @agent1.preferences[:chat] = { + active: { + chat1.id.to_s => 'on', + }, + } + @agent1.save! + @agent2.preferences[:chat] = { + active: { + chat2.id.to_s => 'on', + }, + } + @agent2.save! + + Setting.set('chat', true) + + # check customer state + assert_equal('offline', chat1.customer_state[:state]) + assert_equal('offline', chat2.customer_state[:state]) + + # check agent state + agent_state = Chat.agent_state_with_sessions(@agent1.id) + assert_equal(0, agent_state[:waiting_chat_count]) + assert_equal(0, agent_state[:running_chat_count]) + assert_equal([], agent_state[:active_sessions]) + assert_equal(0, agent_state[:seads_available]) + assert_equal(0, agent_state[:seads_total]) + assert_equal(false, agent_state[:active]) + + # set agent 1 to active + Chat::Agent.create!( + active: true, + concurrent: 4, + updated_by_id: @agent1.id, + created_by_id: @agent1.id, + ) + + # check customer state + assert_equal('online', chat1.customer_state[:state]) + assert_equal('offline', chat2.customer_state[:state]) + + # check agent state + agent_state = Chat.agent_state_with_sessions(@agent2.id) + assert_equal(0, agent_state[:waiting_chat_count]) + assert_equal(0, agent_state[:running_chat_count]) + assert_equal([], agent_state[:active_sessions]) + assert_equal(0, agent_state[:seads_available]) + assert_equal(0, agent_state[:seads_total]) + assert_equal(false, agent_state[:active]) + + # set agent 2 to active + Chat::Agent.create!( + active: true, + concurrent: 2, + updated_by_id: @agent2.id, + created_by_id: @agent2.id, + ) + + # check customer state + assert_equal('online', chat1.customer_state[:state]) + assert_equal('online', chat2.customer_state[:state]) + + # start session + chat_session1 = Chat::Session.create!( + chat_id: chat1.id, + user_id: @agent1.id, + ) + assert(chat_session1.session_id) + + # check agent1 state + agent_state = Chat.agent_state_with_sessions(@agent1.id) + assert_equal(1, agent_state[:waiting_chat_count]) + assert_equal(0, agent_state[:running_chat_count]) + assert_equal([], agent_state[:active_sessions]) + assert_equal(3, agent_state[:seads_available]) + assert_equal(4, agent_state[:seads_total]) + assert_equal(true, agent_state[:active]) + + # check agent2 state + agent_state = Chat.agent_state_with_sessions(@agent2.id) + assert_equal(0, agent_state[:waiting_chat_count]) + assert_equal(0, agent_state[:running_chat_count]) + assert_equal([], agent_state[:active_sessions]) + assert_equal(2, agent_state[:seads_available]) + assert_equal(2, agent_state[:seads_total]) + assert_equal(true, agent_state[:active]) + end + + test 'if agent_active_chat_ids works correctly' do + chat1 = Chat.create!( + name: 'topic 1', + max_queue: 5, + note: '', + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + chat2 = Chat.create!( + name: 'topic 2', + max_queue: 5, + note: '', + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + assert_equal([], Chat.agent_active_chat_ids(@agent1)) + assert_equal([], Chat.agent_active_chat_ids(@agent2)) + + @agent1.preferences[:chat] = { + active: { + chat1.id.to_s => 'on', + }, + } + @agent1.save! + @agent2.preferences[:chat] = { + active: { + chat2.id => 'on', + }, + } + @agent2.save! + assert_equal([chat1.id], Chat.agent_active_chat_ids(@agent1)) + assert_equal([chat2.id], Chat.agent_active_chat_ids(@agent2)) + + @agent2.preferences[:chat] = { + active: { + chat2.id => 'off', + }, + } + @agent2.save! + assert_equal([chat1.id], Chat.agent_active_chat_ids(@agent1)) + assert_equal([], Chat.agent_active_chat_ids(@agent2)) + end + test 'blocked ip test' do chat = Chat.create!( name: 'ip test',