diff --git a/app/models/chat.rb b/app/models/chat.rb
index bd1a4a64a..96988d943 100644
--- a/app/models/chat.rb
+++ b/app/models/chat.rb
@@ -26,7 +26,7 @@ class Chat < ApplicationModel
}
# get queue postion if needed
- session = Chat.session_state(session_id)
+ session = Chat::Session.messages_by_session_id(session_id)
if session
return {
state: 'reconnect',
@@ -51,10 +51,10 @@ class Chat < ApplicationModel
end
# if all seads are used
- if active_chat_count >= max_queue
+ if Chat.active_chat_count >= max_queue
return {
state: 'no_seats_available',
- queue: seads_available,
+ queue: Chat.seads_available,
}
end
@@ -62,32 +62,14 @@ class Chat < ApplicationModel
{ state: 'online' }
end
- def self.session_state(session_id)
- session_attributes = []
- chat_session = Chat::Session.find_by(session_id: session_id)
- return if !chat_session
- Chat::Message.where(chat_session_id: chat_session.id).each { |message|
- session_attributes.push message.attributes
- }
- session_attributes
- end
-
def self.agent_state(user_id)
return { state: 'chat_disabled' } if !Setting.get('chat')
- actice_sessions = []
- Chat::Session.where(state: 'running', user_id: user_id).order('created_at ASC').each {|session|
- session_attributes = session.attributes
- session_attributes['messages'] = []
- Chat::Message.where(chat_session_id: session.id).each { |message|
- session_attributes['messages'].push message.attributes
- }
- actice_sessions.push session_attributes
- }
{
waiting_chat_count: waiting_chat_count,
running_chat_count: running_chat_count,
- #available_agents: available_agents,
- active_sessions: actice_sessions,
+ active_sessions: Chat::Session.active_chats_by_user_id(user_id),
+ seads_available: seads_available,
+ seads_total: seads_total,
active: Chat::Agent.state(user_id)
}
end
@@ -100,11 +82,11 @@ class Chat < ApplicationModel
Chat::Session.where(state: ['running']).count
end
- def active_chat_count
+ def self.active_chat_count
Chat::Session.where(state: %w(waiting running)).count
end
- def available_agents(diff = 2.minutes)
+ def self.available_agents(diff = 2.minutes)
agents = {}
Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each {|record|
agents[record.updated_by_id] = record.concurrent
@@ -112,15 +94,15 @@ class Chat < ApplicationModel
agents
end
- def seads_total(diff = 2.minutes)
+ def self.seads_total(diff = 2.minutes)
total = 0
- available_agents(diff).each {|_record, concurrent|
+ available_agents(diff).each {|_user_id, concurrent|
total += concurrent
}
total
end
- def seads_available(diff = 2.minutes)
+ def self.seads_available(diff = 2.minutes)
seads_total(diff) - active_chat_count
end
end
diff --git a/app/models/chat/session.rb b/app/models/chat/session.rb
index 4932fc1e1..0edd06435 100644
--- a/app/models/chat/session.rb
+++ b/app/models/chat/session.rb
@@ -35,4 +35,27 @@ class Chat::Session < ApplicationModel
}
position
end
+
+ def self.messages_by_session_id(session_id)
+ chat_session = Chat::Session.find_by(session_id: session_id)
+ return if !chat_session
+ session_attributes = []
+ Chat::Message.where(chat_session_id: chat_session.id).each { |message|
+ session_attributes.push message.attributes
+ }
+ session_attributes
+ end
+
+ def self.active_chats_by_user_id(user_id)
+ actice_sessions = []
+ Chat::Session.where(state: 'running', user_id: user_id).order('created_at ASC').each {|session|
+ session_attributes = session.attributes
+ session_attributes['messages'] = []
+ Chat::Message.where(chat_session_id: session.id).each { |message|
+ session_attributes['messages'].push message.attributes
+ }
+ actice_sessions.push session_attributes
+ }
+ actice_sessions
+ end
end
diff --git a/db/migrate/20151113000001_update_chat.rb b/db/migrate/20151113000001_update_chat.rb
new file mode 100644
index 000000000..4cfa73acd
--- /dev/null
+++ b/db/migrate/20151113000001_update_chat.rb
@@ -0,0 +1,9 @@
+class UpdateChat < ActiveRecord::Migration
+ def up
+ add_index :chat_sessions, [:session_id]
+ add_index :chat_sessions, [:chat_id]
+ add_index :chat_messages, [:chat_session_id]
+ add_index :chat_agents, [:active]
+ add_index :chat_agents, [:updated_by_id], unique: true
+ end
+end
diff --git a/lib/sessions/event/chat_base.rb b/lib/sessions/event/chat_base.rb
index e687cf2a8..cdd9f0587 100644
--- a/lib/sessions/event/chat_base.rb
+++ b/lib/sessions/event/chat_base.rb
@@ -4,7 +4,6 @@ class Sessions::Event::ChatBase
@data = data
@session = session
@client_id = client_id
-
end
def pre
@@ -35,4 +34,22 @@ class Sessions::Event::ChatBase
}
end
+ def broadcast_customer_state_update
+
+ # send position update to other waiting sessions
+ position = 0
+ Chat::Session.where(state: 'waiting').order('created_at ASC').each {|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
diff --git a/lib/sessions/event/chat_session_close.rb b/lib/sessions/event/chat_session_close.rb
index d0f0005ad..6827f6a68 100644
--- a/lib/sessions/event/chat_session_close.rb
+++ b/lib/sessions/event/chat_session_close.rb
@@ -49,6 +49,9 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
# set state update to all agents
broadcast_agent_state_update
+ # send position update to other waiting sessions
+ broadcast_customer_state_update
+
# notify about "leaving"
else
message = {
diff --git a/lib/sessions/event/chat_session_start.rb b/lib/sessions/event/chat_session_start.rb
index 4f14df7f9..0480c6259 100644
--- a/lib/sessions/event/chat_session_start.rb
+++ b/lib/sessions/event/chat_session_start.rb
@@ -39,20 +39,9 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
chat_session.send_to_recipients(data)
# send position update to other waiting sessions
- position = 0
- Chat::Session.where(state: 'waiting').order('created_at ASC').each {|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)
- }
+ broadcast_customer_state_update
+ # send state update to agents
broadcast_agent_state_update
nil
diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee
index 4d15ef45c..52a6255dd 100644
--- a/public/assets/chat/chat.coffee
+++ b/public/assets/chat/chat.coffee
@@ -132,12 +132,15 @@ do($ = window.jQuery, window) ->
@log 'debug', 'Zammad Chat: ready'
when 'offline'
@onError 'Zammad Chat: No agent online'
+ @hide()
@wsClose()
when 'chat_disabled'
@onError 'Zammad Chat: Chat is disabled'
+ @hide()
@wsClose()
when 'no_seats_available'
@onError 'Zammad Chat: Too many clients in queue. Clients in queue: ', pipe.data.queue
+ @hide()
@wsClose()
when 'reconnect'
@log 'debug', 'old messages', pipe.data.session
@@ -291,9 +294,6 @@ do($ = window.jQuery, window) ->
if @onInitialQueueDelayId
clearTimeout(@onInitialQueueDelayId)
- sessionStorage.removeItem 'sessionId'
- sessionStorage.removeItem 'unfinished_message'
-
@closeWindow()
closeWindow: =>
@@ -309,6 +309,10 @@ do($ = window.jQuery, window) ->
session_id: @sessionId
@setSessionId undefined
+ sessionStorage.removeItem 'unfinished_message'
+
+ # restart connection
+ @onWebSocketOpen()
hide: ->
@el.removeClass('zammad-chat-is-visible')
diff --git a/public/assets/chat/index.html b/public/assets/chat/index.html
index 1bbc4360d..dc811675e 100644
--- a/public/assets/chat/index.html
+++ b/public/assets/chat/index.html
@@ -2,7 +2,6 @@
Zammad Chat
-
-
+
@@ -142,9 +141,6 @@
host: 'ws://localhost',
port: 6042,
debug: true,
- background: '#494d52',
- flat: true,
- show: false
});
$('.settings :input').on({
diff --git a/public/assets/chat/znuny.html b/public/assets/chat/znuny.html
new file mode 100644
index 000000000..1da94fc28
--- /dev/null
+++ b/public/assets/chat/znuny.html
@@ -0,0 +1,147 @@
+
+
+Zammad Chat
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/unit/chat_test.rb b/test/unit/chat_test.rb
new file mode 100644
index 000000000..1cc260205
--- /dev/null
+++ b/test/unit/chat_test.rb
@@ -0,0 +1,306 @@
+# encoding: utf-8
+require 'test_helper'
+
+class ChatTest < ActiveSupport::TestCase
+
+ # create base
+ groups = Group.all
+ roles = Role.where( name: %w(Agent Chat) )
+ agent1 = User.create_or_update(
+ login: 'ticket-chat-agent1@example.com',
+ firstname: 'Notification',
+ lastname: 'Agent1',
+ email: 'ticket-chat-agent1@example.com',
+ password: 'agentpw',
+ active: true,
+ roles: roles,
+ groups: groups,
+ updated_at: '2015-02-05 16:37:00',
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ agent2 = User.create_or_update(
+ login: 'ticket-chat-agent2@example.com',
+ firstname: 'Notification',
+ lastname: 'Agent2',
+ email: 'ticket-chat-agent2@example.com',
+ password: 'agentpw',
+ active: true,
+ roles: roles,
+ groups: groups,
+ updated_at: '2015-02-05 16:38:00',
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ test 'default test' do
+
+ Chat.delete_all
+ Chat::Topic.delete_all
+ Chat::Session.delete_all
+ Chat::Message.delete_all
+ Chat::Agent.delete_all
+ Setting.set('chat', false)
+ chat = Chat.create(
+ name: 'default',
+ max_queue: 5,
+ note: '',
+ active: true,
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+ chat_topic = Chat::Topic.create(
+ chat_id: chat.id,
+ name: 'default',
+ updated_by_id: 1,
+ created_by_id: 1,
+ )
+
+ # check if feature is disabled
+ assert_equal('chat_disabled', chat.customer_state[:state])
+ assert_equal('chat_disabled', Chat.agent_state(agent1.id)[:state])
+ Setting.set('chat', true)
+
+ # check customer state
+ assert_equal('offline', chat.customer_state[:state])
+
+ # check agent state
+ agent_state = Chat.agent_state(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_agent1 = Chat::Agent.create_or_update(
+ active: true,
+ concurrent: 4,
+ updated_by_id: agent1.id,
+ created_by_id: agent1.id,
+ )
+
+ # check customer state
+ assert_equal('online', chat.customer_state[:state])
+
+ # check agent state
+ agent_state = Chat.agent_state(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(4, agent_state[:seads_available])
+ assert_equal(4, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # start session
+ chat_session1 = Chat::Session.create(
+ chat_id: chat.id,
+ user_id: agent1.id,
+ )
+ assert(chat_session1.session_id)
+
+ # check customer state
+ assert_equal('online', chat.customer_state[:state])
+
+ # check agent state
+ agent_state = Chat.agent_state(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])
+
+ # activate second agent
+ chat_agent2 = Chat::Agent.create_or_update(
+ active: true,
+ concurrent: 2,
+ updated_by_id: agent2.id,
+ created_by_id: agent2.id,
+ )
+
+ # check customer state
+ assert_equal('online', chat.customer_state[:state])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(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(5, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # check agent2 state
+ agent_state = Chat.agent_state(agent2.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(5, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # start next chat
+ chat_session2 = Chat::Session.create(
+ chat_id: chat.id,
+ )
+
+ # check customer state
+ assert_equal('online', chat.customer_state[:state])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(2, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(4, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # check agent2 state
+ agent_state = Chat.agent_state(agent2.id)
+ assert_equal(2, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(4, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # start new chats
+ chat_session3 = Chat::Session.create(
+ chat_id: chat.id,
+ )
+ chat_session4 = Chat::Session.create(
+ chat_id: chat.id,
+ )
+ chat_session5 = Chat::Session.create(
+ chat_id: chat.id,
+ )
+ chat_session6 = Chat::Session.create(
+ chat_id: chat.id,
+ )
+
+ # check customer state
+ assert_equal('no_seats_available', chat.customer_state[:state])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(6, 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(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # check agent2 state
+ agent_state = Chat.agent_state(agent2.id)
+ assert_equal(6, 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(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ chat_session6.state = 'running'
+ chat_session6.save
+
+ # check customer state
+ assert_equal('no_seats_available', chat.customer_state[:state])
+ assert_equal(0, chat.customer_state[:queue])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(1, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(0, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ # check agent2 state
+ agent_state = Chat.agent_state(agent2.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(1, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(0, agent_state[:seads_available])
+ assert_equal(6, agent_state[:seads_total])
+ assert_equal(true, agent_state[:active])
+
+ chat_agent2.active = false
+ chat_agent2.save
+
+ # check customer state
+ assert_equal('no_seats_available', chat.customer_state[:state])
+ assert_equal(-2, chat.customer_state[:queue])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(1, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(-2, 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(agent2.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(1, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(-2, agent_state[:seads_available])
+ assert_equal(4, agent_state[:seads_total])
+ assert_equal(false, agent_state[:active])
+
+ chat_session6.state = 'closed'
+ chat_session6.save
+
+ # check customer state
+ assert_equal('no_seats_available', chat.customer_state[:state])
+ assert_equal(-1, chat.customer_state[:queue])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(-1, 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(agent2.id)
+ assert_equal(5, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(-1, agent_state[:seads_available])
+ assert_equal(4, agent_state[:seads_total])
+ assert_equal(false, agent_state[:active])
+
+ chat_session5.destroy
+ chat_session4.destroy
+
+ # check customer state
+ assert_equal('online', chat.customer_state[:state])
+
+ # check agent1 state
+ agent_state = Chat.agent_state(agent1.id)
+ assert_equal(3, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(1, 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(agent2.id)
+ assert_equal(3, agent_state[:waiting_chat_count])
+ assert_equal(0, agent_state[:running_chat_count])
+ assert_equal([], agent_state[:active_sessions])
+ assert_equal(1, agent_state[:seads_available])
+ assert_equal(4, agent_state[:seads_total])
+ assert_equal(false, agent_state[:active])
+
+ end
+
+end