Implemented issue #2044 - Generic CTI integration.
This commit is contained in:
parent
7966bb3b16
commit
29a0336809
14 changed files with 1075 additions and 14 deletions
158
app/assets/javascripts/app/controllers/_integration/cti.coffee
Normal file
158
app/assets/javascripts/app/controllers/_integration/cti.coffee
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
class Index extends App.ControllerIntegrationBase
|
||||||
|
featureIntegration: 'cti_integration'
|
||||||
|
featureName: 'CTI (generic)'
|
||||||
|
featureConfig: 'cti_config'
|
||||||
|
description: [
|
||||||
|
['This service shows you contacts of incoming calls and a caller list in realtime.']
|
||||||
|
['Also caller id of outbound calls can be changed.']
|
||||||
|
]
|
||||||
|
events:
|
||||||
|
'click .js-select': 'selectAll'
|
||||||
|
'change .js-switch input': 'switch'
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
super
|
||||||
|
new Form(
|
||||||
|
el: @$('.js-form')
|
||||||
|
)
|
||||||
|
|
||||||
|
new App.HttpLog(
|
||||||
|
el: @$('.js-log')
|
||||||
|
facility: 'cti'
|
||||||
|
)
|
||||||
|
|
||||||
|
class Form extends App.Controller
|
||||||
|
events:
|
||||||
|
'submit form': 'update'
|
||||||
|
'click .js-inboundBlockCallerId .js-add': 'addInboundBlockCallerId'
|
||||||
|
'click .js-outboundRouting .js-add': 'addOutboundRouting'
|
||||||
|
'click .js-inboundBlockCallerId .js-remove': 'removeInboundBlockCallerId'
|
||||||
|
'click .js-outboundRouting .js-remove': 'removeOutboundRouting'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@render()
|
||||||
|
|
||||||
|
currentConfig: ->
|
||||||
|
config = App.Setting.get('cti_config')
|
||||||
|
if !config.outbound
|
||||||
|
config.outbound = {}
|
||||||
|
if !config.outbound.routing_table
|
||||||
|
config.outbound.routing_table = []
|
||||||
|
if !config.inbound
|
||||||
|
config.inbound = {}
|
||||||
|
if !config.inbound.block_caller_ids
|
||||||
|
config.inbound.block_caller_ids = []
|
||||||
|
config
|
||||||
|
|
||||||
|
setConfig: (value) ->
|
||||||
|
App.Setting.set('cti_config', value, {notify: true})
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
@config = @currentConfig()
|
||||||
|
|
||||||
|
@html App.view('integration/cti')(
|
||||||
|
config: @config
|
||||||
|
cti_token: App.Setting.get('cti_token')
|
||||||
|
)
|
||||||
|
|
||||||
|
updateCurrentConfig: =>
|
||||||
|
config = @config
|
||||||
|
cleanupInput = @cleanupInput
|
||||||
|
|
||||||
|
# default caller_id
|
||||||
|
default_caller_id = @$('input[name=default_caller_id]').val()
|
||||||
|
config.outbound.default_caller_id = cleanupInput(default_caller_id)
|
||||||
|
|
||||||
|
# routing table
|
||||||
|
config.outbound.routing_table = []
|
||||||
|
@$('.js-outboundRouting .js-row').each(->
|
||||||
|
dest = cleanupInput($(@).find('input[name="dest"]').val())
|
||||||
|
caller_id = cleanupInput($(@).find('input[name="caller_id"]').val())
|
||||||
|
note = $(@).find('input[name="note"]').val()
|
||||||
|
config.outbound.routing_table.push {
|
||||||
|
dest: dest
|
||||||
|
caller_id: caller_id
|
||||||
|
note: note
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# blocked caller ids
|
||||||
|
config.inbound.block_caller_ids = []
|
||||||
|
@$('.js-inboundBlockCallerId .js-row').each(->
|
||||||
|
caller_id = $(@).find('input[name="caller_id"]').val()
|
||||||
|
note = $(@).find('input[name="note"]').val()
|
||||||
|
config.inbound.block_caller_ids.push {
|
||||||
|
caller_id: cleanupInput(caller_id)
|
||||||
|
note: note
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@config = config
|
||||||
|
|
||||||
|
update: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
@setConfig(@config)
|
||||||
|
|
||||||
|
cleanupInput: (value) ->
|
||||||
|
return value if !value
|
||||||
|
value.replace(/\s/g, '').trim()
|
||||||
|
|
||||||
|
addInboundBlockCallerId: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
element = $(e.currentTarget).closest('tr')
|
||||||
|
caller_id = element.find('input[name="caller_id"]').val()
|
||||||
|
note = element.find('input[name="note"]').val()
|
||||||
|
return if _.isEmpty(caller_id) || _.isEmpty(note)
|
||||||
|
@config.inbound.block_caller_ids.push {
|
||||||
|
caller_id: @cleanupInput(caller_id)
|
||||||
|
note: note
|
||||||
|
}
|
||||||
|
@render()
|
||||||
|
|
||||||
|
addOutboundRouting: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
element = $(e.currentTarget).closest('tr')
|
||||||
|
dest = @cleanupInput(element.find('input[name="dest"]').val())
|
||||||
|
caller_id = @cleanupInput(element.find('input[name="caller_id"]').val())
|
||||||
|
note = element.find('input[name="note"]').val()
|
||||||
|
return if _.isEmpty(caller_id) || _.isEmpty(dest) || _.isEmpty(note)
|
||||||
|
@config.outbound.routing_table.push {
|
||||||
|
dest: dest
|
||||||
|
caller_id: caller_id
|
||||||
|
note: note
|
||||||
|
}
|
||||||
|
@render()
|
||||||
|
|
||||||
|
removeInboundBlockCallerId: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
element = $(e.currentTarget).closest('tr')
|
||||||
|
element.remove()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
|
||||||
|
removeOutboundRouting: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
element = $(e.currentTarget).closest('tr')
|
||||||
|
element.remove()
|
||||||
|
@updateCurrentConfig()
|
||||||
|
|
||||||
|
class State
|
||||||
|
@current: ->
|
||||||
|
App.Setting.get('cti_integration')
|
||||||
|
|
||||||
|
App.Config.set(
|
||||||
|
'IntegrationCti'
|
||||||
|
{
|
||||||
|
name: 'CTI (generic)'
|
||||||
|
target: '#system/integration/cti'
|
||||||
|
description: 'Generic API to integrate VoIP service provider with realtime push.'
|
||||||
|
controller: Index
|
||||||
|
state: State
|
||||||
|
}
|
||||||
|
'NavBarIntegrations'
|
||||||
|
)
|
|
@ -112,6 +112,7 @@ class App.CTI extends App.Controller
|
||||||
|
|
||||||
featureActive: =>
|
featureActive: =>
|
||||||
return true if @Config.get('sipgate_integration')
|
return true if @Config.get('sipgate_integration')
|
||||||
|
return true if @Config.get('cti_integration')
|
||||||
false
|
false
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
|
97
app/assets/javascripts/app/views/integration/cti.jst.eco
Normal file
97
app/assets/javascripts/app/views/integration/cti.jst.eco
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<form>
|
||||||
|
|
||||||
|
<h2><%- @T('Settings') %></h2>
|
||||||
|
|
||||||
|
<p><%- @T('You need to configure the Zammad endpoints in the %s', 'PBX') %>:<p>
|
||||||
|
|
||||||
|
<div class="settings-entry">
|
||||||
|
<table class="settings-list" style="width: 100%;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="20%"><%- @T('Type') %>
|
||||||
|
<th width="80%"><%- @T('URL') %>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="settings-list-row-control"><%- @T('Endpoint') %>
|
||||||
|
<td class="settings-list-control-cell"><input type="url" class="form-control form-control--small js-select" readonly value="<%- @C('http_type') %>://<%- @C('fqdn') %>/api/v1/cti/<%= @cti_token %>">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%- @T('Inbound') %></h2>
|
||||||
|
|
||||||
|
<p><%- @T('Blocked caller ids based on sender caller id.') %>
|
||||||
|
|
||||||
|
<div class="settings-entry">
|
||||||
|
<table class="settings-list js-inboundBlockCallerId" style="width: 100%;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50%"><%- @T('Caller id to block') %>
|
||||||
|
<th width="40%"><%- @T('Note') %>
|
||||||
|
<th width="10%"><%- @T('Action') %>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% for row in @config.inbound.block_caller_ids: %>
|
||||||
|
<tr class="js-row">
|
||||||
|
<td class="settings-list-control-cell"><input name="caller_id" value="<%= row.caller_id %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="note" value="<%= row.note %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-row-control"><div class="btn btn--text js-remove"><%- @Icon('trash') %> <%- @T('Remove') %></div>
|
||||||
|
<% end %>
|
||||||
|
<tr>
|
||||||
|
<td class="settings-list-control-cell"><input name="caller_id" value="" placeholder="4930609854189" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="note" value="" placeholder="<%- @Ti('my onw note') %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-row-control"><div class="btn btn--text btn--create js-add"><%- @Icon('plus-small') %> <%- @T('Add') %></div>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%- @T('Outbound') %></h2>
|
||||||
|
|
||||||
|
<p><%- @T('Set caller id of outbound calls based on destination caller id.') %>
|
||||||
|
|
||||||
|
<div class="settings-entry js-outboundRouting">
|
||||||
|
<table class="settings-list" style="width: 100%;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="30%"><%- @T('Destination caller id') %>
|
||||||
|
<th width="30%"><%- @T('Set outbound caller id') %>
|
||||||
|
<th width="30%"><%- @T('Note') %>
|
||||||
|
<th width="10%"><%- @T('Action') %>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% for row in @config.outbound.routing_table: %>
|
||||||
|
<tr class="js-row">
|
||||||
|
<td class="settings-list-control-cell"><input name="dest" value="<%= row.dest %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="caller_id" value="<%= row.caller_id %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="note" value="<%= row.note %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-row-control"><div class="btn btn--text js-remove"><%- @Icon('trash') %> <%- @T('Remove') %></div>
|
||||||
|
<% end %>
|
||||||
|
<tr>
|
||||||
|
<td class="settings-list-control-cell"><input name="dest" value="" placeholder="49* or 3230123456789" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="caller_id" value="" placeholder="4930609854189" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-control-cell"><input name="note" value="" placeholder="<%- @Ti('my onw note') %>" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-row-control"><div class="btn btn--text btn--create js-add"><%- @Icon('plus-small') %> <%- @T('Add') %></div>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><%- @T('Default caller id.') %>
|
||||||
|
|
||||||
|
<div class="settings-entry">
|
||||||
|
<table class="settings-list" style="width: 100%;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50%"><%- @T('Default caller id') %>
|
||||||
|
<th width="50%"><%- @T('Note') %>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="settings-list-control-cell"><input name="default_caller_id" value="<%= @config.outbound.default_caller_id %>" placeholder="4930609854189" class="form-control form-control--small js-summary">
|
||||||
|
<td class="settings-list-row-control"><%- @T('Default caller id for outbound calls.') %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn--primary js-submit"><%- @T('Save') %></button>
|
||||||
|
</form>
|
|
@ -6,6 +6,11 @@ class CtiController < ApplicationController
|
||||||
# list current caller log
|
# list current caller log
|
||||||
def index
|
def index
|
||||||
backends = [
|
backends = [
|
||||||
|
{
|
||||||
|
name: 'CTI (generic)',
|
||||||
|
enabled: Setting.get('cti_integration'),
|
||||||
|
url: '#system/integration/cti',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'sipgate.io',
|
name: 'sipgate.io',
|
||||||
enabled: Setting.get('sipgate_integration'),
|
enabled: Setting.get('sipgate_integration'),
|
||||||
|
|
117
app/controllers/integration/cti_controller.rb
Normal file
117
app/controllers/integration/cti_controller.rb
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class Integration::CtiController < ApplicationController
|
||||||
|
skip_before_action :verify_csrf_token
|
||||||
|
before_action :check_configured, :check_token
|
||||||
|
|
||||||
|
# notify about inbound call / block inbound call
|
||||||
|
def event
|
||||||
|
if params['direction'] == 'in'
|
||||||
|
if params['event'] == 'newCall'
|
||||||
|
config_inbound = config_integration[:inbound] || {}
|
||||||
|
block_caller_ids = config_inbound[:block_caller_ids] || []
|
||||||
|
|
||||||
|
# check if call need to be blocked
|
||||||
|
block_caller_ids.each do |item|
|
||||||
|
next unless item[:caller_id] == params['from']
|
||||||
|
|
||||||
|
render json: { action: 'reject', reason: 'busy' }, status: :ok
|
||||||
|
|
||||||
|
#params['Reject'] = 'busy'
|
||||||
|
params['comment'] = 'reject, busy'
|
||||||
|
if params['user']
|
||||||
|
params['comment'] = "#{params['user']} -> reject, busy"
|
||||||
|
end
|
||||||
|
Cti::Log.process(params)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Cti::Log.process(params)
|
||||||
|
|
||||||
|
render json: {}, status: :ok
|
||||||
|
return true
|
||||||
|
elsif params['direction'] == 'out'
|
||||||
|
config_outbound = config_integration[:outbound]
|
||||||
|
routing_table = nil
|
||||||
|
default_caller_id = nil
|
||||||
|
if config_outbound.present?
|
||||||
|
routing_table = config_outbound[:routing_table]
|
||||||
|
default_caller_id = config_outbound[:default_caller_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
# set callerId
|
||||||
|
data = {}
|
||||||
|
to = params[:to]
|
||||||
|
from = nil
|
||||||
|
if to && routing_table.present?
|
||||||
|
routing_table.each do |row|
|
||||||
|
dest = row[:dest].gsub(/\*/, '.+?')
|
||||||
|
next if to !~ /^#{dest}$/
|
||||||
|
from = row[:caller_id]
|
||||||
|
data = {
|
||||||
|
action: 'dial',
|
||||||
|
caller_id: from,
|
||||||
|
number: params[:to]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if data.blank? && default_caller_id.present?
|
||||||
|
from = default_caller_id
|
||||||
|
data = {
|
||||||
|
action: 'dial',
|
||||||
|
caller_id: default_caller_id,
|
||||||
|
number: params[:to]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
render json: data, status: :ok
|
||||||
|
|
||||||
|
if from.present?
|
||||||
|
params['from'] = from
|
||||||
|
end
|
||||||
|
Cti::Log.process(params)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
render json: { error: 'Invalid direction!' }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_token
|
||||||
|
if Setting.get('cti_token') != params[:token]
|
||||||
|
response_unauthorized('Invalid token, please contact your admin!')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_configured
|
||||||
|
http_log_config facility: 'cti'
|
||||||
|
|
||||||
|
if !Setting.get('cti_integration')
|
||||||
|
response_error('Feature is disable, please contact your admin to enable it!')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if config_integration.blank? || config_integration[:inbound].blank? || config_integration[:outbound].blank?
|
||||||
|
response_error('Feature not configured, please contact your admin!')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def config_integration
|
||||||
|
@config_integration ||= Setting.get('cti_config')
|
||||||
|
end
|
||||||
|
|
||||||
|
def response_error(error)
|
||||||
|
render json: { error: error }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
def response_unauthorized(error)
|
||||||
|
render json: { error: error }, status: :unauthorized
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -276,7 +276,7 @@ Cti::Log.process(
|
||||||
'user' => 'user 1',
|
'user' => 'user 1',
|
||||||
'from' => '4912347114711',
|
'from' => '4912347114711',
|
||||||
'to' => '4930600000000',
|
'to' => '4930600000000',
|
||||||
'callId' => '4991155921769858278-1',
|
'callId' => '4991155921769858278-1', # or call_id
|
||||||
'direction' => 'in',
|
'direction' => 'in',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -286,6 +286,7 @@ Cti::Log.process(
|
||||||
comment = params['cause']
|
comment = params['cause']
|
||||||
event = params['event']
|
event = params['event']
|
||||||
user = params['user']
|
user = params['user']
|
||||||
|
call_id = params['callId'] || params['call_id']
|
||||||
if user.class == Array
|
if user.class == Array
|
||||||
user = user.join(', ')
|
user = user.join(', ')
|
||||||
end
|
end
|
||||||
|
@ -309,14 +310,14 @@ Cti::Log.process(
|
||||||
from_comment: from_comment,
|
from_comment: from_comment,
|
||||||
to: params['to'],
|
to: params['to'],
|
||||||
to_comment: to_comment,
|
to_comment: to_comment,
|
||||||
call_id: params['callId'],
|
call_id: call_id,
|
||||||
comment: comment,
|
comment: comment,
|
||||||
state: event,
|
state: event,
|
||||||
preferences: preferences,
|
preferences: preferences,
|
||||||
)
|
)
|
||||||
when 'answer'
|
when 'answer'
|
||||||
log = find_by(call_id: params['callId'])
|
log = find_by(call_id: call_id)
|
||||||
raise "No such call_id #{params['callId']}" if !log
|
raise "No such call_id #{call_id}" if !log
|
||||||
log.state = 'answer'
|
log.state = 'answer'
|
||||||
log.start = Time.zone.now
|
log.start = Time.zone.now
|
||||||
if user
|
if user
|
||||||
|
@ -325,8 +326,8 @@ Cti::Log.process(
|
||||||
log.comment = comment
|
log.comment = comment
|
||||||
log.save
|
log.save
|
||||||
when 'hangup'
|
when 'hangup'
|
||||||
log = find_by(call_id: params['callId'])
|
log = find_by(call_id: call_id)
|
||||||
raise "No such call_id #{params['callId']}" if !log
|
raise "No such call_id #{call_id}" if !log
|
||||||
if params['direction'] == 'in' && log.state == 'newCall'
|
if params['direction'] == 'in' && log.state == 'newCall'
|
||||||
log.done = false
|
log.done = false
|
||||||
end
|
end
|
||||||
|
|
5
config/routes/integration_cti.rb
Normal file
5
config/routes/integration_cti.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
|
||||||
|
match '/api/v1/cti/:token', to: 'integration/cti#event', via: :post
|
||||||
|
|
||||||
|
end
|
70
db/migrate/20180420000001_setting_cti.rb
Normal file
70
db/migrate/20180420000001_setting_cti.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
class SettingCti < ActiveRecord::Migration[5.1]
|
||||||
|
def up
|
||||||
|
|
||||||
|
# return if it's a new setup
|
||||||
|
return if !Setting.find_by(name: 'system_init_done')
|
||||||
|
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'cti integration',
|
||||||
|
name: 'cti_integration',
|
||||||
|
area: 'Integration::Switch',
|
||||||
|
description: 'Defines if generic CTI is enabled or not.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'cti_integration',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: false,
|
||||||
|
preferences: {
|
||||||
|
prio: 1,
|
||||||
|
trigger: ['menu:render', 'cti:reload'],
|
||||||
|
authentication: true,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: true
|
||||||
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'cti config',
|
||||||
|
name: 'cti_config',
|
||||||
|
area: 'Integration::Cti',
|
||||||
|
description: 'Defines the cti config.',
|
||||||
|
options: {},
|
||||||
|
state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
|
||||||
|
preferences: {
|
||||||
|
prio: 2,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: false,
|
||||||
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'CTI Token',
|
||||||
|
name: 'cti_token',
|
||||||
|
area: 'Integration::Cti',
|
||||||
|
description: 'Token for cti.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'cti_token',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: SecureRandom.urlsafe_base64(20),
|
||||||
|
preferences: {
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -2485,7 +2485,7 @@ Setting.create_if_not_exists(
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
state: SecureRandom.urlsafe_base64(40),
|
state: ENV['MONITORING_TOKEN'] || SecureRandom.urlsafe_base64(40),
|
||||||
preferences: {
|
preferences: {
|
||||||
permission: ['admin.monitoring'],
|
permission: ['admin.monitoring'],
|
||||||
},
|
},
|
||||||
|
@ -3377,7 +3377,7 @@ Setting.create_if_not_exists(
|
||||||
area: 'Core',
|
area: 'Core',
|
||||||
description: 'Defines the Check_MK token for allowing updates.',
|
description: 'Defines the Check_MK token for allowing updates.',
|
||||||
options: {},
|
options: {},
|
||||||
state: SecureRandom.hex(16),
|
state: ENV['CHECK_MK_TOKEN'] || SecureRandom.hex(16),
|
||||||
preferences: {
|
preferences: {
|
||||||
permission: ['admin.integration'],
|
permission: ['admin.integration'],
|
||||||
},
|
},
|
||||||
|
@ -3722,6 +3722,68 @@ Setting.create_if_not_exists(
|
||||||
},
|
},
|
||||||
frontend: false,
|
frontend: false,
|
||||||
)
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'cti integration',
|
||||||
|
name: 'cti_integration',
|
||||||
|
area: 'Integration::Switch',
|
||||||
|
description: 'Defines if generic CTI is enabled or not.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: true,
|
||||||
|
name: 'cti_integration',
|
||||||
|
tag: 'boolean',
|
||||||
|
options: {
|
||||||
|
true => 'yes',
|
||||||
|
false => 'no',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: false,
|
||||||
|
preferences: {
|
||||||
|
prio: 1,
|
||||||
|
trigger: ['menu:render', 'cti:reload'],
|
||||||
|
authentication: true,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: true
|
||||||
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'cti config',
|
||||||
|
name: 'cti_config',
|
||||||
|
area: 'Integration::Cti',
|
||||||
|
description: 'Defines the cti config.',
|
||||||
|
options: {},
|
||||||
|
state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
|
||||||
|
preferences: {
|
||||||
|
prio: 2,
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: false,
|
||||||
|
)
|
||||||
|
Setting.create_if_not_exists(
|
||||||
|
title: 'CTI Token',
|
||||||
|
name: 'cti_token',
|
||||||
|
area: 'Integration::Cti',
|
||||||
|
description: 'Token for cti.',
|
||||||
|
options: {
|
||||||
|
form: [
|
||||||
|
{
|
||||||
|
display: '',
|
||||||
|
null: false,
|
||||||
|
name: 'cti_token',
|
||||||
|
tag: 'input',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
state: ENV['CTI_TOKEN'] || SecureRandom.urlsafe_base64(20),
|
||||||
|
preferences: {
|
||||||
|
permission: ['admin.integration'],
|
||||||
|
},
|
||||||
|
frontend: false
|
||||||
|
)
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
title: 'Clearbit integration',
|
title: 'Clearbit integration',
|
||||||
name: 'clearbit_integration',
|
name: 'clearbit_integration',
|
||||||
|
|
|
@ -5,3 +5,4 @@ set -ex
|
||||||
rm app/assets/javascripts/app/controllers/layout_ref.coffee
|
rm app/assets/javascripts/app/controllers/layout_ref.coffee
|
||||||
rm -rf app/assets/javascripts/app/views/layout_ref/
|
rm -rf app/assets/javascripts/app/views/layout_ref/
|
||||||
rm app/assets/javascripts/app/controllers/karma.coffee
|
rm app/assets/javascripts/app/controllers/karma.coffee
|
||||||
|
rm app/assets/javascripts/app/controllers/_integration/cti.coffee
|
||||||
|
|
|
@ -65,7 +65,8 @@ if [ "$LEVEL" == '1' ]; then
|
||||||
# test/browser/maintenance_session_message_test.rb
|
# test/browser/maintenance_session_message_test.rb
|
||||||
# test/browser/manage_test.rb
|
# test/browser/manage_test.rb
|
||||||
# test/browser/monitoring_test.rb
|
# test/browser/monitoring_test.rb
|
||||||
rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
rm test/browser/preferences_language_test.rb
|
rm test/browser/preferences_language_test.rb
|
||||||
rm test/browser/preferences_permission_check_test.rb
|
rm test/browser/preferences_permission_check_test.rb
|
||||||
rm test/browser/preferences_token_access_test.rb
|
rm test/browser/preferences_token_access_test.rb
|
||||||
|
@ -138,7 +139,8 @@ elif [ "$LEVEL" == '2' ]; then
|
||||||
rm test/browser/maintenance_session_message_test.rb
|
rm test/browser/maintenance_session_message_test.rb
|
||||||
rm test/browser/manage_test.rb
|
rm test/browser/manage_test.rb
|
||||||
rm test/browser/monitoring_test.rb
|
rm test/browser/monitoring_test.rb
|
||||||
rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
rm test/browser/preferences_language_test.rb
|
rm test/browser/preferences_language_test.rb
|
||||||
rm test/browser/preferences_permission_check_test.rb
|
rm test/browser/preferences_permission_check_test.rb
|
||||||
rm test/browser/preferences_token_access_test.rb
|
rm test/browser/preferences_token_access_test.rb
|
||||||
|
@ -211,7 +213,8 @@ elif [ "$LEVEL" == '3' ]; then
|
||||||
rm test/browser/maintenance_session_message_test.rb
|
rm test/browser/maintenance_session_message_test.rb
|
||||||
rm test/browser/manage_test.rb
|
rm test/browser/manage_test.rb
|
||||||
rm test/browser/monitoring_test.rb
|
rm test/browser/monitoring_test.rb
|
||||||
rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
rm test/browser/preferences_language_test.rb
|
rm test/browser/preferences_language_test.rb
|
||||||
rm test/browser/preferences_permission_check_test.rb
|
rm test/browser/preferences_permission_check_test.rb
|
||||||
rm test/browser/preferences_token_access_test.rb
|
rm test/browser/preferences_token_access_test.rb
|
||||||
|
@ -284,7 +287,8 @@ elif [ "$LEVEL" == '4' ]; then
|
||||||
rm test/browser/maintenance_session_message_test.rb
|
rm test/browser/maintenance_session_message_test.rb
|
||||||
rm test/browser/manage_test.rb
|
rm test/browser/manage_test.rb
|
||||||
rm test/browser/monitoring_test.rb
|
rm test/browser/monitoring_test.rb
|
||||||
rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
rm test/browser/preferences_language_test.rb
|
rm test/browser/preferences_language_test.rb
|
||||||
rm test/browser/preferences_permission_check_test.rb
|
rm test/browser/preferences_permission_check_test.rb
|
||||||
rm test/browser/preferences_token_access_test.rb
|
rm test/browser/preferences_token_access_test.rb
|
||||||
|
@ -356,7 +360,8 @@ elif [ "$LEVEL" == '5' ]; then
|
||||||
rm test/browser/maintenance_session_message_test.rb
|
rm test/browser/maintenance_session_message_test.rb
|
||||||
rm test/browser/manage_test.rb
|
rm test/browser/manage_test.rb
|
||||||
rm test/browser/monitoring_test.rb
|
rm test/browser/monitoring_test.rb
|
||||||
rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
rm test/browser/preferences_language_test.rb
|
rm test/browser/preferences_language_test.rb
|
||||||
rm test/browser/preferences_permission_check_test.rb
|
rm test/browser/preferences_permission_check_test.rb
|
||||||
rm test/browser/preferences_token_access_test.rb
|
rm test/browser/preferences_token_access_test.rb
|
||||||
|
@ -431,7 +436,8 @@ elif [ "$LEVEL" == '6' ]; then
|
||||||
rm test/browser/maintenance_session_message_test.rb
|
rm test/browser/maintenance_session_message_test.rb
|
||||||
rm test/browser/manage_test.rb
|
rm test/browser/manage_test.rb
|
||||||
rm test/browser/monitoring_test.rb
|
rm test/browser/monitoring_test.rb
|
||||||
# rm test/browser/phone_notify_not_clearing_on_leftside_test.rb
|
# rm test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb
|
||||||
|
# rm test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb
|
||||||
# test/browser/preferences_language_test.rb
|
# test/browser/preferences_language_test.rb
|
||||||
# test/browser/preferences_permission_check_test.rb
|
# test/browser/preferences_permission_check_test.rb
|
||||||
# test/browser/preferences_token_access_test.rb
|
# test/browser/preferences_token_access_test.rb
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
require 'browser_test_helper'
|
||||||
|
|
||||||
|
# Regression test for #2017
|
||||||
|
|
||||||
|
class IntegrationCtiNotifyNotClearingOnLeftsideTest < TestCase
|
||||||
|
setup do
|
||||||
|
if !ENV['CTI_TOKEN']
|
||||||
|
raise "ERROR: Need CTI_TOKEN - hint CTI_TOKEN='some_token'"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_notify_badge
|
||||||
|
id = rand(99_999_999)
|
||||||
|
|
||||||
|
@browser = browser_instance
|
||||||
|
login(
|
||||||
|
username: 'master@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#manage"]')
|
||||||
|
click(css: 'a[href="#system/integration"]')
|
||||||
|
click(css: 'a[href="#system/integration/cti"]')
|
||||||
|
|
||||||
|
switch(
|
||||||
|
css: '.content.active .js-switch',
|
||||||
|
type: 'on'
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
css: 'a[href="#cti"]'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#cti"]')
|
||||||
|
|
||||||
|
# simulate cti callbacks
|
||||||
|
|
||||||
|
url = URI.join(browser_url, "api/v1/cti/#{ENV['CTI_TOKEN']}")
|
||||||
|
params = { direction: 'in', from: '491715000002', to: '4930600000000', callId: "4991155921769858278-#{id}", cause: 'busy' }
|
||||||
|
Net::HTTP.post_form(url, params.merge(event: 'newCall'))
|
||||||
|
Net::HTTP.post_form(url, params.merge(event: 'hangup'))
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
css: '.js-phoneMenuItem .counter',
|
||||||
|
value: '1'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: '.content.active .table-checkbox label')
|
||||||
|
|
||||||
|
watch_for_disappear(
|
||||||
|
css: '.js-phoneMenuItem .counter'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#manage"]')
|
||||||
|
click(css: 'a[href="#system/integration"]')
|
||||||
|
click(css: 'a[href="#system/integration/cti"]')
|
||||||
|
|
||||||
|
switch(
|
||||||
|
css: '.content.active .js-switch',
|
||||||
|
type: 'off'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,58 @@
|
||||||
|
require 'browser_test_helper'
|
||||||
|
|
||||||
|
# Regression test for #2017
|
||||||
|
|
||||||
|
class IntegrationSipgateNotifyNotClearingOnLeftsideTest < TestCase
|
||||||
|
def test_notify_badge
|
||||||
|
id = rand(99_999_999)
|
||||||
|
|
||||||
|
@browser = browser_instance
|
||||||
|
login(
|
||||||
|
username: 'master@example.com',
|
||||||
|
password: 'test',
|
||||||
|
url: browser_url,
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#manage"]')
|
||||||
|
click(css: 'a[href="#system/integration"]')
|
||||||
|
click(css: 'a[href="#system/integration/sipgate"]')
|
||||||
|
|
||||||
|
switch(
|
||||||
|
css: '.content.active .js-switch',
|
||||||
|
type: 'on'
|
||||||
|
)
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
css: 'a[href="#cti"]'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#cti"]')
|
||||||
|
|
||||||
|
# simulate sipgate callbacks
|
||||||
|
|
||||||
|
url = URI.join(browser_url, 'api/v1/sipgate/in')
|
||||||
|
params = { direction: 'in', from: '491715000002', to: '4930600000000', callId: "4991155921769858278-#{id}", cause: 'busy' }
|
||||||
|
Net::HTTP.post_form(url, params.merge(event: 'newCall'))
|
||||||
|
Net::HTTP.post_form(url, params.merge(event: 'hangup'))
|
||||||
|
|
||||||
|
watch_for(
|
||||||
|
css: '.js-phoneMenuItem .counter',
|
||||||
|
value: '1'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: '.content.active .table-checkbox label')
|
||||||
|
|
||||||
|
watch_for_disappear(
|
||||||
|
css: '.js-phoneMenuItem .counter'
|
||||||
|
)
|
||||||
|
|
||||||
|
click(css: 'a[href="#manage"]')
|
||||||
|
click(css: 'a[href="#system/integration"]')
|
||||||
|
click(css: 'a[href="#system/integration/cti"]')
|
||||||
|
|
||||||
|
switch(
|
||||||
|
css: '.content.active .js-switch',
|
||||||
|
type: 'off'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
415
test/controllers/integration_cti_controller_test.rb
Normal file
415
test/controllers/integration_cti_controller_test.rb
Normal file
|
@ -0,0 +1,415 @@
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
class IntegrationCtiControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
|
||||||
|
Cti::Log.destroy_all
|
||||||
|
|
||||||
|
Setting.set('cti_integration', true)
|
||||||
|
Setting.set('cti_config', {
|
||||||
|
outbound: {
|
||||||
|
routing_table: [
|
||||||
|
{
|
||||||
|
dest: '41*',
|
||||||
|
caller_id: '41715880339000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dest: '491714000000',
|
||||||
|
caller_id: '41715880339000',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default_caller_id: '4930777000000',
|
||||||
|
},
|
||||||
|
inbound: {
|
||||||
|
block_caller_ids: [
|
||||||
|
{
|
||||||
|
caller_id: '491715000000',
|
||||||
|
note: 'some note',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
notify_user_ids: {
|
||||||
|
2 => true,
|
||||||
|
4 => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},)
|
||||||
|
|
||||||
|
groups = Group.where(name: 'Users')
|
||||||
|
roles = Role.where(name: %w[Agent])
|
||||||
|
agent = User.create_or_update(
|
||||||
|
login: 'cti-agent@example.com',
|
||||||
|
firstname: 'E',
|
||||||
|
lastname: 'S',
|
||||||
|
email: 'cti-agent@example.com',
|
||||||
|
password: 'agentpw',
|
||||||
|
active: true,
|
||||||
|
roles: roles,
|
||||||
|
groups: groups,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
customer1 = User.create_or_update(
|
||||||
|
login: 'ticket-caller_id_cti-customer1@example.com',
|
||||||
|
firstname: 'CallerId',
|
||||||
|
lastname: 'Customer1',
|
||||||
|
email: 'ticket-caller_id_cti-customer1@example.com',
|
||||||
|
password: 'customerpw',
|
||||||
|
active: true,
|
||||||
|
phone: '+49 99999 222222',
|
||||||
|
fax: '+49 99999 222223',
|
||||||
|
mobile: '+4912347114711',
|
||||||
|
note: 'Phone at home: +49 99999 222224',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
customer2 = User.create_or_update(
|
||||||
|
login: 'ticket-caller_id_cti-customer2@example.com',
|
||||||
|
firstname: 'CallerId',
|
||||||
|
lastname: 'Customer2',
|
||||||
|
email: 'ticket-caller_id_cti-customer2@example.com',
|
||||||
|
password: 'customerpw',
|
||||||
|
active: true,
|
||||||
|
phone: '+49 99999 222222 2',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
customer3 = User.create_or_update(
|
||||||
|
login: 'ticket-caller_id_cti-customer3@example.com',
|
||||||
|
firstname: 'CallerId',
|
||||||
|
lastname: 'Customer3',
|
||||||
|
email: 'ticket-caller_id_cti-customer3@example.com',
|
||||||
|
password: 'customerpw',
|
||||||
|
active: true,
|
||||||
|
phone: '+49 99999 222222 2',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
Cti::CallerId.rebuild
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'token check' do
|
||||||
|
params = 'event=newCall&direction=in&from=4912347114711&to=4930600000000&call_id=4991155921769858278-1&user%5B%5D=user+1&user%5B%5D=user+2'
|
||||||
|
post '/api/v1/cti/not_existing_token', params: params
|
||||||
|
assert_response(401)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Invalid token, please contact your admin!', result['error'])
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'basic call' do
|
||||||
|
token = Setting.get('cti_token')
|
||||||
|
|
||||||
|
# inbound - I
|
||||||
|
params = 'event=newCall&direction=in&from=4912347114711&to=4930600000000&call_id=4991155921769858278-1&user%5B%5D=user+1&user%5B%5D=user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert(result.blank?)
|
||||||
|
|
||||||
|
# inbound - II - block caller
|
||||||
|
params = 'event=newCall&direction=in&from=491715000000&to=4930600000000&call_id=4991155921769858278-2&user%5B%5D=user+1&user%5B%5D=user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('reject', result['action'])
|
||||||
|
assert_equal('busy', result['reason'])
|
||||||
|
|
||||||
|
# outbound - I - set default_caller_id
|
||||||
|
params = 'event=newCall&direction=out&from=4930600000000&to=4912347114711&call_id=8621106404543334274-3&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('dial', result['action'])
|
||||||
|
assert_equal('4912347114711', result['number'])
|
||||||
|
assert_equal('4930777000000', result['caller_id'])
|
||||||
|
|
||||||
|
# outbound - II - set caller_id based on routing_table by explicite number
|
||||||
|
params = 'event=newCall&direction=out&from=4930600000000&to=491714000000&call_id=8621106404543334274-4&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('dial', result['action'])
|
||||||
|
assert_equal('491714000000', result['number'])
|
||||||
|
assert_equal('41715880339000', result['caller_id'])
|
||||||
|
|
||||||
|
# outbound - III - set caller_id based on routing_table by 41*
|
||||||
|
params = 'event=newCall&direction=out&from=4930600000000&to=4147110000000&call_id=8621106404543334274-5&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('dial', result['action'])
|
||||||
|
assert_equal('4147110000000', result['number'])
|
||||||
|
assert_equal('41715880339000', result['caller_id'])
|
||||||
|
|
||||||
|
# no config
|
||||||
|
Setting.set('cti_config', {})
|
||||||
|
params = 'event=newCall&direction=in&from=4912347114711&to=4930600000000&call_id=4991155921769858278-6&user%5B%5D=user+1&user%5B%5D=user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(Hash, result.class)
|
||||||
|
assert_equal('Feature not configured, please contact your admin!', result['error'])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'log call' do
|
||||||
|
token = Setting.get('cti_token')
|
||||||
|
|
||||||
|
# outbound - I - new call
|
||||||
|
params = 'event=newCall&direction=out&from=4930600000000&to=4912347114711&call_id=1234567890-1&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-1')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930777000000', log.from)
|
||||||
|
assert_equal('4912347114711', log.to)
|
||||||
|
assert_equal('out', log.direction)
|
||||||
|
assert_equal('user 1', log.from_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# outbound - I - hangup by agent
|
||||||
|
params = 'event=hangup&direction=out&call_id=1234567890-1&cause=cancel'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-1')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930777000000', log.from)
|
||||||
|
assert_equal('4912347114711', log.to)
|
||||||
|
assert_equal('out', log.direction)
|
||||||
|
assert_equal('user 1', log.from_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.to_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&call_id=1234567890-2&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-2')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930777000000', log.from)
|
||||||
|
assert_equal('4912347114711', log.to)
|
||||||
|
assert_equal('out', log.direction)
|
||||||
|
assert_equal('user 1', log.from_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# outbound - II - answer by customer
|
||||||
|
params = 'event=answer&direction=out&call_id=1234567890-2&from=4930600000000&to=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-2')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930777000000', log.from)
|
||||||
|
assert_equal('4912347114711', log.to)
|
||||||
|
assert_equal('out', log.direction)
|
||||||
|
assert_equal('user 1', log.from_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.to_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('answer', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# outbound - II - hangup by customer
|
||||||
|
params = 'event=hangup&direction=out&call_id=1234567890-2&cause=normalClearing&from=4930600000000&to=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-2')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930777000000', log.from)
|
||||||
|
assert_equal('4912347114711', log.to)
|
||||||
|
assert_equal('out', log.direction)
|
||||||
|
assert_equal('user 1', log.from_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.to_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&call_id=1234567890-3&user%5B%5D=user+1'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-3')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930600000000', log.to)
|
||||||
|
assert_equal('4912347114711', log.from)
|
||||||
|
assert_equal('in', log.direction)
|
||||||
|
assert_equal('user 1', log.to_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# inbound - I - answer by customer
|
||||||
|
params = 'event=answer&direction=in&call_id=1234567890-3&to=4930600000000&from=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-3')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930600000000', log.to)
|
||||||
|
assert_equal('4912347114711', log.from)
|
||||||
|
assert_equal('in', log.direction)
|
||||||
|
assert_equal('user 1', log.to_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.from_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('answer', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# inbound - I - hangup by customer
|
||||||
|
params = 'event=hangup&direction=in&call_id=1234567890-3&cause=normalClearing&to=4930600000000&from=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-3')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930600000000', log.to)
|
||||||
|
assert_equal('4912347114711', log.from)
|
||||||
|
assert_equal('in', log.direction)
|
||||||
|
assert_equal('user 1', log.to_comment)
|
||||||
|
assert_equal('CallerId Customer1', log.from_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&call_id=1234567890-4&user%5B%5D=user+1,user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: 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('CallerId Customer1', log.from_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# inbound - II - answer by voicemail
|
||||||
|
params = 'event=answer&direction=in&call_id=1234567890-4&to=4930600000000&from=4912347114711&user=voicemail'
|
||||||
|
post "/api/v1/cti/#{token}", params: 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('CallerId Customer1', log.from_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('answer', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# inbound - II - hangup by customer
|
||||||
|
params = 'event=hangup&direction=in&call_id=1234567890-4&cause=normalClearing&to=4930600000000&from=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: 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('CallerId Customer1', log.from_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&call_id=1234567890-5&user%5B%5D=user+1,user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: 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('CallerId Customer1', log.from_comment)
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# inbound - III - hangup by customer
|
||||||
|
params = 'event=hangup&direction=in&call_id=1234567890-5&cause=normalClearing&to=4930600000000&from=4912347114711'
|
||||||
|
post "/api/v1/cti/#{token}", params: 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('CallerId Customer1', log.from_comment)
|
||||||
|
assert_equal('normalClearing', log.comment)
|
||||||
|
assert_equal('hangup', log.state)
|
||||||
|
assert_equal(false, log.done)
|
||||||
|
|
||||||
|
# inbound - IV - new call
|
||||||
|
params = 'event=newCall&direction=in&to=4930600000000&from=49999992222222&call_id=1234567890-6&user%5B%5D=user+1,user+2'
|
||||||
|
post "/api/v1/cti/#{token}", params: params
|
||||||
|
assert_response(200)
|
||||||
|
log = Cti::Log.find_by(call_id: '1234567890-6')
|
||||||
|
assert(log)
|
||||||
|
assert_equal('4930600000000', log.to)
|
||||||
|
assert_equal('49999992222222', log.from)
|
||||||
|
assert_equal('in', log.direction)
|
||||||
|
assert_equal('user 1,user 2', log.to_comment)
|
||||||
|
assert_equal('CallerId Customer3,CallerId Customer2', log.from_comment)
|
||||||
|
assert_not(log.preferences['to'])
|
||||||
|
assert(log.preferences['from'])
|
||||||
|
assert_nil(log.comment)
|
||||||
|
assert_equal('newCall', log.state)
|
||||||
|
assert_equal(true, log.done)
|
||||||
|
|
||||||
|
# get caller list
|
||||||
|
get '/api/v1/cti/log'
|
||||||
|
assert_response(401)
|
||||||
|
|
||||||
|
customer2 = User.lookup(login: 'ticket-caller_id_cti-customer2@example.com')
|
||||||
|
customer3 = User.lookup(login: 'ticket-caller_id_cti-customer3@example.com')
|
||||||
|
|
||||||
|
headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('cti-agent@example.com', 'agentpw')
|
||||||
|
get '/api/v1/cti/log', headers: headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert_equal(result['list'].class, Array)
|
||||||
|
assert_equal(6, result['list'].count)
|
||||||
|
assert(result['assets'])
|
||||||
|
assert(result['assets']['User'])
|
||||||
|
assert(result['assets']['User'][customer2.id.to_s])
|
||||||
|
assert(result['assets']['User'][customer3.id.to_s])
|
||||||
|
assert_equal('1234567890-6', result['list'][0]['call_id'])
|
||||||
|
assert_equal('1234567890-5', result['list'][1]['call_id'])
|
||||||
|
assert_equal('1234567890-4', result['list'][2]['call_id'])
|
||||||
|
assert_equal('1234567890-3', result['list'][3]['call_id'])
|
||||||
|
assert_equal('1234567890-2', result['list'][4]['call_id'])
|
||||||
|
assert_equal('hangup', result['list'][4]['state'])
|
||||||
|
assert_equal('4930777000000', result['list'][4]['from'])
|
||||||
|
assert_equal('user 1', result['list'][4]['from_comment'])
|
||||||
|
assert_equal('4912347114711', result['list'][4]['to'])
|
||||||
|
assert_equal('CallerId Customer1', result['list'][4]['to_comment'])
|
||||||
|
assert_equal('normalClearing', result['list'][4]['comment'])
|
||||||
|
assert_equal('hangup', result['list'][4]['state'])
|
||||||
|
assert_equal('1234567890-1', result['list'][5]['call_id'])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue