Browse Source

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

Martin Edenhofer 6 years ago
parent
commit
a2c52538be

+ 2 - 0
app/assets/javascripts/app/controllers/_integration/placetel.coffee

@@ -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)

+ 16 - 0
app/assets/javascripts/app/views/integration/placetel.jst.eco

@@ -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.') %>

+ 65 - 0
app/controllers/integration/placetel_controller.rb

@@ -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

+ 13 - 2
app/models/setting.rb

@@ -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

+ 21 - 15
db/migrate/20180921000001_setting_add_placetel.rb → db/migrate/20181030000001_setting_add_placetel1.rb

@@ -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,19 +32,26 @@ class SettingAddPlacetel < ActiveRecord::Migration[5.1]
       },
       frontend: true
     )
-    Setting.create_if_not_exists(
-      title: 'Placetel config',
-      name: 'placetel_config',
-      area: 'Integration::Placetel',
-      description: 'Defines the Placetel config.',
-      options: {},
-      state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
-      preferences: {
-        prio: 2,
-        permission: ['admin.integration'],
-      },
-      frontend: false,
-    )
+    placetel_config = Setting.find_by(name: 'placetel_config')
+    if !placetel_config
+      Setting.create!(
+        title: 'Placetel config',
+        name: 'placetel_config',
+        area: 'Integration::Placetel',
+        description: 'Defines the Placetel config.',
+        options: {},
+        state: { 'outbound' => { 'routing_table' => [], 'default_caller_id' => '' }, 'inbound' => { 'block_caller_ids' => [] } },
+        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

+ 2 - 1
db/seeds/settings.rb

@@ -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: [
       {

+ 0 - 1
script/build/cleanup.sh

@@ -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

+ 68 - 14
spec/requests/integration/placetel_spec.rb

@@ -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 - 0
test/unit/setting_test.rb

@@ -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