Enabled Placetel integration. Added user info via Placetel API lookup (optional).

This commit is contained in:
Martin Edenhofer 2018-10-30 17:00:33 +01:00
parent 66e8d58f29
commit a2c52538be
9 changed files with 250 additions and 33 deletions

View file

@ -60,6 +60,8 @@ class Form extends App.Controller
config = @config
cleanupInput = @cleanupInput
config.api_token = @$('input[name=api_token]').val()
# default caller_id
default_caller_id = @$('input[name=default_caller_id]').val()
config.outbound.default_caller_id = cleanupInput(default_caller_id)

View file

@ -19,6 +19,22 @@
</table>
</div>
<p><%- @T('In order for Zammad to access %s, the %s API token must be stored here', 'Placetel', 'Placetel') %>:<p>
<div class="settings-entry">
<table class="settings-list" style="width: 100%;">
<thead>
<tr>
<th width="20%"><%- @T('Type') %>
<th width="80%"><%- @T('Content') %>
</thead>
<tbody>
<tr>
<td class="settings-list-row-control"><%- @T('API Token') %>
<td class="settings-list-control-cell"><input type="input" class="form-control form-control--small js-select" value="<%= @config.api_token %>" name="api_token" placeholder="">
</tbody>
</table>
</div>
<h2><%- @T('Inbound') %></h2>
<p><%- @T('Blocked caller ids based on sender caller id.') %>

View file

@ -20,6 +20,10 @@ class Integration::PlacetelController < ApplicationController
local_params['event'] = 'answer'
end
if local_params['user'].blank? && local_params['peer']
local_params['user'] = get_voip_user_by_peer(local_params['peer'])
end
if local_params['direction'].blank?
entry = Cti::Log.find_by(call_id: params[:call_id])
if entry
@ -164,4 +168,65 @@ class Integration::PlacetelController < ApplicationController
xml_error(error, 401)
end
def get_voip_user_by_peer(peer)
load_voip_users[peer]
end
def load_voip_users
return {} if config_integration.blank? || config_integration[:api_token].blank?
list = Cache.get('placetelGetVoipUsers')
return list if list
response = UserAgent.post(
'https://api.placetel.de/api/getVoIPUsers.json',
{
api_key: config_integration[:api_token],
},
{
log: {
facility: 'placetel',
},
json: true,
open_timeout: 4,
read_timeout: 6,
total_timeout: 6,
},
)
if !response.success?
logger.error "Can't fetch getVoipUsers from '#{url}', http code: #{response.code}"
Cache.write('placetelGetVoipUsers', {}, { expires_in: 1.hour })
return {}
end
result = response.data
if result.blank?
logger.error "Can't fetch getVoipUsers from '#{url}', result: #{response.inspect}"
Cache.write('placetelGetVoipUsers', {}, { expires_in: 1.hour })
return {}
end
if result.is_a?(Hash) && (result['result'] == '-1' || result['result_code'] == 'error')
logger.error "Can't fetch getVoipUsers from '#{url}', result: #{result.inspect}"
Cache.write('placetelGetVoipUsers', {}, { expires_in: 1.hour })
return {}
end
if !result.is_a?(Array)
logger.error "Can't fetch getVoipUsers from '#{url}', result: #{result.inspect}"
Cache.write('placetelGetVoipUsers', {}, { expires_in: 1.hour })
return {}
end
list = {}
result.each do |entry|
next if entry['name'].blank?
if entry['uid'].present?
list[entry['uid']] = entry['name']
end
next if entry['uid2'].blank?
list[entry['uid2']] = entry['name']
end
Cache.write('placetelGetVoipUsers', list, { expires_in: 24.hours })
list
end
end

View file

@ -7,8 +7,8 @@ class Setting < ApplicationModel
store :preferences
before_create :state_check, :set_initial, :check_broadcast
before_update :state_check, :check_broadcast
after_create :reset_change_id
after_update :reset_change_id
after_create :reset_change_id, :reset_cache
after_update :reset_change_id, :reset_cache
attr_accessor :state
@ -40,6 +40,7 @@ set config setting
setting.state_current = { value: value }
setting.save!
logger.info "Setting.set('#{name}', #{value.inspect})"
true
end
=begin
@ -75,6 +76,7 @@ reset config setting to default
setting.state_current = setting.state_initial
setting.save!
logger.info "Setting.reset('#{name}', #{setting.state_current.inspect})"
true
end
=begin
@ -145,6 +147,15 @@ reload config settings
true
end
def reset_cache
return true if preferences[:cache].blank?
preferences[:cache].each do |key|
Cache.delete(key)
end
true
end
# check if cache is still valid
def self.cache_valid?
if @@lookup_at && @@lookup_at > Time.zone.now - @@lookup_timeout

View file

@ -1,4 +1,4 @@
class SettingAddPlacetel < ActiveRecord::Migration[5.1]
class SettingAddPlacetel1 < ActiveRecord::Migration[5.1]
def change
# return if it's a new setup
@ -32,7 +32,9 @@ class SettingAddPlacetel < ActiveRecord::Migration[5.1]
},
frontend: true
)
Setting.create_if_not_exists(
placetel_config = Setting.find_by(name: 'placetel_config')
if !placetel_config
Setting.create!(
title: 'Placetel config',
name: 'placetel_config',
area: 'Integration::Placetel',
@ -42,9 +44,14 @@ class SettingAddPlacetel < ActiveRecord::Migration[5.1]
preferences: {
prio: 2,
permission: ['admin.integration'],
cache: ['placetelGetVoipUsers'],
},
frontend: false,
)
else
placetel_config.preferences[:cache] = ['placetelGetVoipUsers']
placetel_config.save!
end
Setting.create_if_not_exists(
title: 'PLACETEL Token',
name: 'placetel_token',
@ -66,6 +73,5 @@ class SettingAddPlacetel < ActiveRecord::Migration[5.1]
},
frontend: false
)
end
end

View file

@ -4034,6 +4034,7 @@ Setting.create_if_not_exists(
preferences: {
prio: 2,
permission: ['admin.integration'],
cache: ['placetelGetVoipUsers'],
},
frontend: false,
)
@ -4041,7 +4042,7 @@ Setting.create_if_not_exists(
title: 'PLACETEL Token',
name: 'placetel_token',
area: 'Integration::Placetel',
description: 'Token for placetel.',
description: 'Token for Placetel.',
options: {
form: [
{

View file

@ -5,4 +5,3 @@ set -ex
rm app/assets/javascripts/app/controllers/layout_ref.coffee
rm -rf app/assets/javascripts/app/views/layout_ref/
rm app/assets/javascripts/app/controllers/karma.coffee
rm app/assets/javascripts/app/controllers/_integration/placetel.coffee

View file

@ -187,7 +187,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
#expect(log.from_comment).to eq('user 1')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
@ -207,7 +207,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
#expect(log.from_comment).to eq('user 1')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to eq('cancel')
expect(log.state).to eq('hangup')
@ -227,7 +227,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
# expect(log.from_comment).to eq('user 1')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
@ -247,7 +247,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
# expect(log.from_comment).to eq('user 1')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('answer')
@ -267,7 +267,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
# expect(log.from_comment).to eq('user 1')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to eq('normalClearing')
expect(log.state).to eq('hangup')
@ -287,7 +287,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
@ -307,7 +307,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('answer')
@ -327,7 +327,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to eq('normalClearing')
expect(log.state).to eq('hangup')
@ -347,7 +347,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1,user 2')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
@ -407,7 +407,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1,user 2')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
@ -427,7 +427,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('01114100300')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1,user 2')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer1')
expect(log.comment).to eq('normalClearing')
expect(log.state).to eq('hangup')
@ -447,7 +447,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('49999992222222')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1,user 2')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to eq('CallerId Customer3,CallerId Customer2')
expect(log.preferences['to']).to be_falsey
expect(log.preferences['from']).to be_truthy
@ -469,7 +469,7 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(log.to).to eq('030600000000')
expect(log.from).to eq('anonymous')
expect(log.direction).to eq('in')
#expect(log.to_comment).to eq('user 1,user 2')
expect(log.to_comment).to eq(nil)
expect(log.from_comment).to be_nil
expect(log.preferences['to']).to be_falsey
expect(log.preferences['from']).to be_falsey
@ -503,12 +503,66 @@ RSpec.describe 'Integration Placetel', type: :request do
expect(json_response['list'][5]['call_id']).to eq('1234567890-2')
expect(json_response['list'][5]['state']).to eq('hangup')
expect(json_response['list'][5]['from']).to eq('4930777000000')
#expect(json_response['list'][5]['from_comment']).to eq('user 1')
expect(json_response['list'][5]['from_comment']).to eq(nil)
expect(json_response['list'][5]['to']).to eq('01114100300')
expect(json_response['list'][5]['to_comment']).to eq('CallerId Customer1')
expect(json_response['list'][5]['comment']).to eq('normalClearing')
expect(json_response['list'][5]['state']).to eq('hangup')
expect(json_response['list'][6]['call_id']).to eq('1234567890-1')
end
it 'does log call with peer' do
token = Setting.get('placetel_token')
# outbound - I - new call
params = 'event=newCall&direction=out&from=030600000000&to=01114100300&call_id=1234567890-1&peer=something@example.com'
post "/api/v1/placetel/#{token}", params: params
expect(response).to have_http_status(200)
log = Cti::Log.find_by(call_id: '1234567890-1')
expect(log).to be_truthy
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
expect(log.from_comment).to eq(nil)
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
expect(log.done).to eq(true)
expect(log.initialized_at).to be_truthy
expect(log.start_at).to be_nil
expect(log.end_at).to be_nil
expect(log.duration_waiting_time).to be_nil
expect(log.duration_talking_time).to be_nil
config = Setting.get('placetel_config')
config[:api_token] = '123'
Setting.set('placetel_config', config)
stub_request(:post, 'https://api.placetel.de/api/getVoIPUsers.json')
.to_return(status: 200, body: [{ 'callerid' => '03055571600', 'did' => 10, 'name' => 'Bob Smith', 'stype' => 3, 'uid' => '777008478072@example.com', 'uid2' => nil }, { 'callerid' => '03055571600', 'did' => 12, 'name' => 'Josef Müller', 'stype' => 3, 'uid' => '777042617425@example.com', 'uid2' => nil }].to_json)
params = 'event=newCall&direction=out&from=030600000000&to=01114100300&call_id=1234567890-2&peer=777008478072@example.com'
post "/api/v1/placetel/#{token}", params: params
expect(response).to have_http_status(200)
log = Cti::Log.find_by(call_id: '1234567890-2')
expect(log).to be_truthy
expect(log.from).to eq('4930777000000')
expect(log.to).to eq('01114100300')
expect(log.direction).to eq('out')
expect(log.from_comment).to eq('Bob Smith')
expect(log.to_comment).to eq('CallerId Customer1')
expect(log.comment).to be_nil
expect(log.state).to eq('newCall')
expect(log.done).to eq(true)
expect(log.initialized_at).to be_truthy
expect(log.start_at).to be_nil
expect(log.end_at).to be_nil
expect(log.duration_waiting_time).to be_nil
expect(log.duration_talking_time).to be_nil
# check if cache is filled
expect(Cache.get('placetelGetVoipUsers')['777008478072@example.com']).to eq('Bob Smith')
end
end
end

63
test/unit/setting_test.rb Normal file
View file

@ -0,0 +1,63 @@
require 'test_helper'
class SettingTest < ActiveSupport::TestCase
test 'basics' do
Setting.create!(
title: 'ABC API Token',
name: 'abc_api_token',
area: 'Integration::ABC',
description: 'API Token for ABC to access ABC.',
options: {
form: [
{
display: '',
null: false,
name: 'abc_token',
tag: 'input',
},
],
},
state: 'abc',
frontend: false
)
assert_equal(Setting.get('abc_api_token'), 'abc')
assert(Setting.set('abc_api_token', 'new_abc'))
assert_equal(Setting.get('abc_api_token'), 'new_abc')
assert(Setting.reset('abc_api_token'))
assert_equal(Setting.get('abc_api_token'), 'abc')
end
test 'cache reset via preferences' do
Setting.create!(
title: 'ABC API Token',
name: 'abc_api_token',
area: 'Integration::ABC',
description: 'API Token for ABC to access ABC.',
options: {
form: [
{
display: '',
null: false,
name: 'abc_token',
tag: 'input',
},
],
},
state: '',
preferences: {
permission: ['admin.integration'],
cache: ['abcGetVoipUsers'],
},
frontend: false
)
Cache.write('abcGetVoipUsers', { a: 1 })
assert_equal(Cache.get('abcGetVoipUsers'), { a: 1 })
Setting.set('abc_api_token', 'some_new_value')
assert_nil(Cache.get('abcGetVoipUsers'))
end
end