diff --git a/app/assets/javascripts/app/controllers/cti.coffee b/app/assets/javascripts/app/controllers/cti.coffee
index 08b09ec27..cd8ebf3a4 100644
--- a/app/assets/javascripts/app/controllers/cti.coffee
+++ b/app/assets/javascripts/app/controllers/cti.coffee
@@ -1,9 +1,17 @@
class App.CTI extends App.Controller
+ events:
+ 'click .js-check': 'done'
+
constructor: ->
super
+ return if !@isRole('CTI')
+
+ @list = []
@meta =
active: false
+ counter: 0
+ state: {}
preferences = @Session.get('preferences') || {}
@meta.active = preferences.cti || false
@@ -14,9 +22,20 @@ class App.CTI extends App.Controller
'cti_event'
(data) =>
console.log('cti_event', data)
- if data.state is 'newCall'
- console.log('notify')
- @notify(data)
+ if data.direction is 'in'
+ if data.state is 'newCall'
+ if @switch()
+ @notify(data)
+ return if @meta.state[data.id]
+ @meta.state[data.id] = true
+ @meta.counter += 1
+ @updateNavMenu()
+ if data.state is 'answer' || data.state is 'hangup'
+ return if !@meta.state[data.id]
+ delete @meta.state[data.id]
+ @meta.counter -= 1
+ @updateNavMenu()
+
'cti_event'
)
App.Event.bind(
@@ -26,6 +45,11 @@ class App.CTI extends App.Controller
@render()
'cti_list_push'
)
+ App.Event.bind(
+ 'auth'
+ (data) =>
+ @meta.counter = 0
+ )
# fetch data, render view
load: ->
@@ -39,14 +63,11 @@ class App.CTI extends App.Controller
)
notify: (data) ->
- console.log(data)
- #return if !
- if data.state is 'newCall' && data.direction is 'in'
- App.Event.trigger 'notify', {
- type: 'notice'
- msg: App.i18n.translateContent('Call from %s for %s', data.from, data.to)
- timeout: 2500
- }
+ App.Event.trigger 'notify', {
+ type: 'notice'
+ msg: App.i18n.translateContent('Call from %s for %s', data.from, data.to)
+ timeout: 12000
+ }
featureActive: =>
return true
@@ -59,18 +80,48 @@ class App.CTI extends App.Controller
@renderScreenUnauthorized(objectName: 'CTI')
return
+ format = (time) ->
+ # Minutes and seconds
+ mins = ~~(time / 60)
+ secs = time % 60
+
+ # Hours, minutes and seconds
+ hrs = ~~(time / 3600)
+ mins = ~~((time % 3600) / 60)
+ secs = time % 60
+
+ # Output like "1:01" or "4:03:59" or "123:03:59"
+ mins = "0#{mins}" if mins < 10
+ secs = "0#{secs}" if secs < 10
+ if hrs > 0
+ return "#{hrs}:#{mins}:#{secs}"
+ "#{mins}:#{secs}"
+
+ for item in @list
+ if item.start && item.end
+ item.duration = format((Date.parse(item.end) - Date.parse(item.start))/1000)
@html App.view('cti/index')(
list: @list
)
@updateNavMenu()
+ done: (e) =>
+ element = $(e.currentTarget)
+ id = element.closest('tr').data('id')
+ done = element.prop('checked')
+ @ajax(
+ type: 'POST'
+ url: "#{@apiPath}/cti/done/#{id}"
+ data: JSON.stringify(done: done)
+ )
+
show: (params) =>
@title 'CTI', true
@navupdate '#cti'
- counter: ->
- counter = 0
+ counter: =>
+ @meta.counter
switch: (state = undefined) =>
diff --git a/app/assets/javascripts/app/views/cti/index.jst.eco b/app/assets/javascripts/app/views/cti/index.jst.eco
index 7aba99b57..313bb3b05 100644
--- a/app/assets/javascripts/app/views/cti/index.jst.eco
+++ b/app/assets/javascripts/app/views/cti/index.jst.eco
@@ -5,20 +5,24 @@
+ |
<%- @T('From') %> |
<%- @T('To') %> |
<%- @T('State') %> |
<%- @T('Comment') %> |
+ <%- @T('Duration') %> |
<%- @T('Time') %> |
<% for item in @list: %>
-
- <%= item.from %><% if item.from_comment: %> (<%= item.from_comment %>)<% end %> |
- <%= item.to %><% if item.to_comment: %> (<%= item.to_comment %>)<% end %> |
+
class="is-inactive"<% end %> data-id="<%- item.id %>">
+ <% if item.state is 'hangup': %>checked<% end %>><% end %>
+ | <% if item.from_comment: %><%= item.from_comment %> <% end %><%= item.from %> |
+ <% if item.to_comment: %><%= item.to_comment %> <% end %><%= item.to %> |
<%= item.state %> |
<%= item.comment %> |
+ <%= item.duration %> |
<%- @humanTime(item.created_at) %> |
<% end %>
diff --git a/app/controllers/integration/sipgate_controller.rb b/app/controllers/integration/sipgate_controller.rb
index 0cbf6f518..6e2e9d51e 100644
--- a/app/controllers/integration/sipgate_controller.rb
+++ b/app/controllers/integration/sipgate_controller.rb
@@ -12,6 +12,16 @@ class Integration::SipgateController < ApplicationController
render json: list
end
+ # set caller log to done
+ def done
+ return if !authentication_check
+ return if deny_if_not_role('CTI')
+ log = Cti::Log.find(params['id'])
+ log.done = params['done']
+ log.save
+ render json: {}
+ end
+
# notify about inbound call / block inbound call
def in
http_log_config facility: 'sipgate.io'
@@ -143,12 +153,23 @@ class Integration::SipgateController < ApplicationController
log = Cti::Log.find_by(call_id: params['callId'])
raise "No such call_id #{params['callId']}" if !log
log.state = 'answer'
+ log.start = Time.zone.now
+ if user
+ log.to_comment = user
+ end
log.comment = comment
log.save
elsif params['event'] == 'hangup'
log = Cti::Log.find_by(call_id: params['callId'])
raise "No such call_id #{params['callId']}" if !log
+ if params['direction'] == 'in' && log.state == 'newCall'
+ log.done = false
+ end
+ if params['direction'] == 'in' && log.to_comment == 'voicemail'
+ log.done = false
+ end
log.state = 'hangup'
+ log.end = Time.zone.now
log.comment = comment
log.save
else
diff --git a/config/routes/integration_sipgate.rb b/config/routes/integration_sipgate.rb
index d569898d2..f6594554b 100644
--- a/config/routes/integration_sipgate.rb
+++ b/config/routes/integration_sipgate.rb
@@ -1,7 +1,8 @@
Zammad::Application.routes.draw do
match '/api/v1/cti/log', to: 'integration/sipgate#index', via: :get
- match '/api/v1/sipgate/in', to: 'integration/sipgate#in', via: :post
- match '/api/v1/sipgate/out', to: 'integration/sipgate#out', via: :post
+ match '/api/v1/cti/done/:id', to: 'integration/sipgate#done', via: :post
+ match '/api/v1/sipgate/in', to: 'integration/sipgate#in', via: :post
+ match '/api/v1/sipgate/out', to: 'integration/sipgate#out', via: :post
end
diff --git a/db/migrate/20160427000001_update_cti_log.rb b/db/migrate/20160427000001_update_cti_log.rb
new file mode 100644
index 000000000..85c3d5eb9
--- /dev/null
+++ b/db/migrate/20160427000001_update_cti_log.rb
@@ -0,0 +1,7 @@
+class UpdateCtiLog < ActiveRecord::Migration
+ def up
+ add_column :cti_logs, :start, :timestamp, null: true
+ add_column :cti_logs, :end, :timestamp, null: true
+ add_column :cti_logs, :done, :boolean, null: false, default: true
+ end
+end
diff --git a/test/integration/sipgate_controller_test.rb b/test/integration/sipgate_controller_test.rb
index 98fb66ecc..a48fdeb0f 100644
--- a/test/integration/sipgate_controller_test.rb
+++ b/test/integration/sipgate_controller_test.rb
@@ -68,7 +68,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
)
groups = Group.where(name: 'Users')
- roles = Role.where(name: 'Agent')
+ roles = Role.where(name: %w(Agent CTI))
agent = User.create_or_update(
login: 'cti-agent@example.com',
firstname: 'E',
@@ -225,6 +225,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.from_comment)
assert_equal(nil, log.comment)
assert_equal('newCall', log.state)
+ assert_equal(true, log.done)
# outbound - I - hangup by agent
params = 'event=hangup&direction=out&callId=1234567890-1&cause=cancel'
@@ -238,6 +239,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.from_comment)
assert_equal('cancel', log.comment)
assert_equal('hangup', log.state)
+ assert_equal(true, log.done)
# outbound - II - new call
params = 'event=newCall&direction=out&from=4930600000000&to=4912347114711&callId=1234567890-2&user%5B%5D=user+1'
@@ -251,6 +253,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.from_comment)
assert_equal(nil, log.comment)
assert_equal('newCall', log.state)
+ assert_equal(true, log.done)
# outbound - II - answer by customer
params = 'event=answer&direction=out&callId=1234567890-2&from=4930600000000&to=4912347114711'
@@ -264,6 +267,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.from_comment)
assert_equal(nil, log.comment)
assert_equal('answer', log.state)
+ assert_equal(true, log.done)
# outbound - II - hangup by customer
params = 'event=hangup&direction=out&callId=1234567890-2&cause=normalClearing&from=4930600000000&to=4912347114711'
@@ -277,6 +281,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.from_comment)
assert_equal('normalClearing', log.comment)
assert_equal('hangup', log.state)
+ assert_equal(true, log.done)
# inbound - I - new call
params = 'event=newCall&direction=in&to=4930600000000&from=4912347114711&callId=1234567890-3&user%5B%5D=user+1'
@@ -290,6 +295,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.to_comment)
assert_equal(nil, log.comment)
assert_equal('newCall', log.state)
+ assert_equal(true, log.done)
# inbound - I - answer by customer
params = 'event=answer&direction=in&callId=1234567890-3&to=4930600000000&from=4912347114711'
@@ -303,6 +309,7 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.to_comment)
assert_equal(nil, log.comment)
assert_equal('answer', log.state)
+ assert_equal(true, log.done)
# inbound - I - hangup by customer
params = 'event=hangup&direction=in&callId=1234567890-3&cause=normalClearing&to=4930600000000&from=4912347114711'
@@ -316,7 +323,79 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_equal('user 1', log.to_comment)
assert_equal('normalClearing', log.comment)
assert_equal('hangup', log.state)
+ assert_equal(true, log.done)
+ # inbound - II - new call
+ params = 'event=newCall&direction=in&to=4930600000000&from=4912347114711&callId=1234567890-4&user%5B%5D=user+1,user+2'
+ post '/api/v1/sipgate/in', params
+ assert_response(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ assert(log)
+ assert_equal('4930600000000', log.to)
+ assert_equal('4912347114711', log.from)
+ assert_equal('in', log.direction)
+ assert_equal('user 1,user 2', log.to_comment)
+ assert_equal(nil, log.comment)
+ assert_equal('newCall', log.state)
+ assert_equal(true, log.done)
+
+ # inbound - II - answer by voicemail
+ params = 'event=answer&direction=in&callId=1234567890-4&to=4930600000000&from=4912347114711&user=voicemail'
+ post '/api/v1/sipgate/in', params
+ assert_response(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ assert(log)
+ assert_equal('4930600000000', log.to)
+ assert_equal('4912347114711', log.from)
+ assert_equal('in', log.direction)
+ assert_equal('voicemail', log.to_comment)
+ assert_equal(nil, log.comment)
+ assert_equal('answer', log.state)
+ assert_equal(true, log.done)
+
+ # inbound - II - hangup by customer
+ params = 'event=hangup&direction=in&callId=1234567890-4&cause=normalClearing&to=4930600000000&from=4912347114711'
+ post '/api/v1/sipgate/in', params
+ assert_response(200)
+ log = Cti::Log.find_by(call_id: '1234567890-4')
+ assert(log)
+ assert_equal('4930600000000', log.to)
+ assert_equal('4912347114711', log.from)
+ assert_equal('in', log.direction)
+ assert_equal('voicemail', log.to_comment)
+ assert_equal('normalClearing', log.comment)
+ assert_equal('hangup', log.state)
+ assert_equal(false, log.done)
+
+ # inbound - III - new call
+ params = 'event=newCall&direction=in&to=4930600000000&from=4912347114711&callId=1234567890-5&user%5B%5D=user+1,user+2'
+ post '/api/v1/sipgate/in', params
+ assert_response(200)
+ log = Cti::Log.find_by(call_id: '1234567890-5')
+ assert(log)
+ assert_equal('4930600000000', log.to)
+ assert_equal('4912347114711', log.from)
+ assert_equal('in', log.direction)
+ assert_equal('user 1,user 2', log.to_comment)
+ assert_equal(nil, log.comment)
+ assert_equal('newCall', log.state)
+ assert_equal(true, log.done)
+
+ # inbound - III - hangup by customer
+ params = 'event=hangup&direction=in&callId=1234567890-5&cause=normalClearing&to=4930600000000&from=4912347114711'
+ post '/api/v1/sipgate/in', params
+ assert_response(200)
+ log = Cti::Log.find_by(call_id: '1234567890-5')
+ assert(log)
+ assert_equal('4930600000000', log.to)
+ assert_equal('4912347114711', log.from)
+ assert_equal('in', log.direction)
+ assert_equal('user 1,user 2', log.to_comment)
+ assert_equal('normalClearing', log.comment)
+ assert_equal('hangup', log.state)
+ assert_equal(false, log.done)
+
+ # get caller list
get '/api/v1/cti/log'
assert_response(401)
@@ -326,7 +405,15 @@ class SipgateControllerTest < ActionDispatch::IntegrationTest
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(result.class, Array)
- assert_equal(3, result.count)
+ assert_equal(5, result.count)
+ assert_equal('hangup', result[1]['state'])
+ assert_equal('4930777000000', result[1]['from'])
+ assert_equal('user 1', result[1]['from_comment'])
+ assert_equal('4912347114711', result[1]['to'])
+ assert_equal(nil, result[1]['to_comment'])
+ assert_equal('1234567890-2', result[1]['call_id'])
+ assert_equal('normalClearing', result[1]['comment'])
+ assert_equal('hangup', result[1]['state'])
end