Browse Source

Prettify phone numbers displayed in Call Log

Ryan Lue 6 years ago
parent
commit
312278c2d6

+ 3 - 0
Gemfile

@@ -100,6 +100,9 @@ gem 'browser'
 gem 'icalendar'
 gem 'icalendar-recurrence'
 
+# feature - phone number formatting
+gem 'telephone_number'
+
 # integrations
 gem 'clearbit'
 gem 'net-ldap'

+ 3 - 1
Gemfile.lock

@@ -413,6 +413,7 @@ GEM
     sqlite3 (1.3.13)
     telegramAPI (1.4.2)
       rest-client (~> 2.0, >= 2.0.2)
+    telephone_number (1.3.0)
     term-ansicolor (1.6.0)
       tins (~> 1.0)
     test-unit (3.2.6)
@@ -542,6 +543,7 @@ DEPENDENCIES
   sprockets
   sqlite3
   telegramAPI
+  telephone_number
   test-unit
   therubyracer
   twitter
@@ -557,4 +559,4 @@ RUBY VERSION
    ruby 2.4.4p296
 
 BUNDLED WITH
-   1.16.1
+   1.16.2

+ 4 - 4
app/assets/javascripts/app/views/cti/caller_log.jst.eco

@@ -40,9 +40,9 @@
           <br>
         <% end %>
         <% if shown: %>
-          <small><%= item.from %></small>
+          <small><%= item.from_pretty %></small>
         <% else: %>
-          <span class="js-userNew u-clickable" href="#"><%= item.from %></span>
+          <span class="js-userNew u-clickable" href="#"><%= item.from_pretty %></span>
         <% end %>
       </td>
       <td>
@@ -66,9 +66,9 @@
           <br>
         <% end %>
         <% if shown: %>
-          <small><%= item.to %></small>
+          <small><%= item.to_pretty %></small>
         <% else: %>
-          <%= item.to %>
+          <%= item.to_pretty %>
         <% end %>
       </td>
       <td style="vertical-align: middle">

+ 26 - 13
app/models/cti/log.rb

@@ -246,19 +246,12 @@ returns
       list = Cti::Log.order('created_at DESC, id DESC').limit(60)
 
       # add assets
-      assets = {}
-      list.each do |item|
-        next if !item.preferences
-        %w[from to].each do |direction|
-          next if !item.preferences[direction]
-          item.preferences[direction].each do |caller_id|
-            next if !caller_id['user_id']
-            user = User.lookup(id: caller_id['user_id'])
-            next if !user
-            assets = user.assets(assets)
-          end
-        end
-      end
+      assets = list.map(&:preferences)
+                   .map { |p| p.slice(:from, :to) }
+                   .map(&:values).flatten
+                   .map { |caller_id| caller_id[:user_id] }.compact
+                   .map { |user_id| User.lookup(id: user_id) }.compact
+                   .each.with_object({}) { |user, a| user.assets(a) }
 
       {
         list: list,
@@ -392,5 +385,25 @@ optional you can put the max oldest chat entries as argument
       true
     end
 
+    # adds virtual attributes when rendering #to_json
+    # see http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
+    def attributes
+      virtual_attributes = {
+        'from_pretty' => from_pretty,
+        'to_pretty' => to_pretty,
+      }
+
+      super.merge(virtual_attributes)
+    end
+
+    def from_pretty
+      parsed = TelephoneNumber.parse(from&.sub(/^\+?/, '+'))
+      parsed.send(parsed.valid? ? :international_number : :original_number)
+    end
+
+    def to_pretty
+      parsed = TelephoneNumber.parse(to&.sub(/^\+?/, '+'))
+      parsed.send(parsed.valid? ? :international_number : :original_number)
+    end
   end
 end

+ 12 - 12
script/build/test_slice_tests.sh

@@ -65,8 +65,8 @@ if [ "$LEVEL" == '1' ]; then
   # test/browser/maintenance_session_message_test.rb
   # test/browser/manage_test.rb
   # test/browser/monitoring_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/integration_sipgate_test.rb
+  rm test/browser/integration_cti_test.rb
   rm test/browser/preferences_language_test.rb
   rm test/browser/preferences_permission_check_test.rb
   rm test/browser/preferences_token_access_test.rb
@@ -139,8 +139,8 @@ elif [ "$LEVEL" == '2' ]; then
   rm test/browser/maintenance_session_message_test.rb
   rm test/browser/manage_test.rb
   rm test/browser/monitoring_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/integration_sipgate_test.rb
+  rm test/browser/integration_cti_test.rb
   rm test/browser/preferences_language_test.rb
   rm test/browser/preferences_permission_check_test.rb
   rm test/browser/preferences_token_access_test.rb
@@ -213,8 +213,8 @@ elif [ "$LEVEL" == '3' ]; then
   rm test/browser/maintenance_session_message_test.rb
   rm test/browser/manage_test.rb
   rm test/browser/monitoring_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/integration_sipgate_test.rb
+  rm test/browser/integration_cti_test.rb
   rm test/browser/preferences_language_test.rb
   rm test/browser/preferences_permission_check_test.rb
   rm test/browser/preferences_token_access_test.rb
@@ -287,8 +287,8 @@ elif [ "$LEVEL" == '4' ]; then
   rm test/browser/maintenance_session_message_test.rb
   rm test/browser/manage_test.rb
   rm test/browser/monitoring_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/integration_sipgate_test.rb
+  rm test/browser/integration_cti_test.rb
   rm test/browser/preferences_language_test.rb
   rm test/browser/preferences_permission_check_test.rb
   rm test/browser/preferences_token_access_test.rb
@@ -360,8 +360,8 @@ elif [ "$LEVEL" == '5' ]; then
   rm test/browser/maintenance_session_message_test.rb
   rm test/browser/manage_test.rb
   rm test/browser/monitoring_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/integration_sipgate_test.rb
+  rm test/browser/integration_cti_test.rb
   rm test/browser/preferences_language_test.rb
   rm test/browser/preferences_permission_check_test.rb
   rm test/browser/preferences_token_access_test.rb
@@ -436,8 +436,8 @@ elif [ "$LEVEL" == '6' ]; then
   rm test/browser/maintenance_session_message_test.rb
   rm test/browser/manage_test.rb
   rm test/browser/monitoring_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/integration_sipgate_test.rb
+  # rm test/browser/integration_cti_test.rb
   # test/browser/preferences_language_test.rb
   # test/browser/preferences_permission_check_test.rb
   # test/browser/preferences_token_access_test.rb

+ 9 - 0
spec/factories/cti/log.rb

@@ -0,0 +1,9 @@
+FactoryBot.define do
+  factory :cti_log, class: 'cti/log' do
+    direction { %w[in out].sample }
+    state     { %w[newCall answer hangup].sample }
+    from      '4930609854180'
+    to        '4930609811111'
+    call_id   { (Cti::Log.pluck(:call_id).max || '0').next } # has SQL UNIQUE constraint
+  end
+end

+ 46 - 0
spec/models/cti/log.rb

@@ -0,0 +1,46 @@
+require 'rails_helper'
+
+RSpec.describe Cti::Log do
+  subject { create(:cti_log, **factory_attributes) }
+  let(:factory_attributes) { {} }
+
+  context 'with complete, E164 international numbers' do
+    let(:factory_attributes) { { from: '4930609854180', to: '4930609811111' } }
+
+    describe '#from_pretty' do
+      it 'gives the number in prettified format' do
+        expect(subject.from_pretty).to eq('+49 30 609854180')
+      end
+    end
+
+    describe '#to_pretty' do
+      it 'gives the number in prettified format' do
+        expect(subject.to_pretty).to eq('+49 30 609811111')
+      end
+    end
+  end
+
+  context 'with private network numbers' do
+    let(:factory_attributes) { { from: '007', to: '008' } }
+
+    describe '#from_pretty' do
+      it 'gives the number unaltered' do
+        expect(subject.from_pretty).to eq('007')
+      end
+    end
+
+    describe '#to_pretty' do
+      it 'gives the number unaltered' do
+        expect(subject.to_pretty).to eq('008')
+      end
+    end
+  end
+
+  describe '#to_json' do
+    let(:virtual_attributes) { %w[from_pretty to_pretty] }
+
+    it 'includes virtual attributes' do
+      expect(subject.as_json).to include(*virtual_attributes)
+    end
+  end
+end

+ 0 - 65
test/browser/integration_cti_notify_not_clearing_on_leftside_test.rb

@@ -1,65 +0,0 @@
-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

+ 147 - 0
test/browser/integration_cti_test.rb

@@ -0,0 +1,147 @@
+require 'browser_test_helper'
+
+class IntegrationCtiTest < TestCase
+  setup do
+    if !ENV['CTI_TOKEN']
+      raise "ERROR: Need CTI_TOKEN - hint CTI_TOKEN='some_token'"
+    end
+
+  end
+
+  # Regression test for #2017
+  def test_nav_menu_notification_badge_clears
+    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"]')
+
+    call_counter = @browser.find_elements(css: '.js-phoneMenuItem .counter')
+                           .first&.text.to_i
+
+    # 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: (call_counter + 1).to_s
+    )
+
+    click(css: '.content.active .table-checkbox label', all: true)
+
+    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
+
+  # Regression test for #2018
+  def test_e164_numbers_displayed_in_prettified_format
+    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']}")
+
+    # ...for private network number
+    params = {
+      direction: 'in',
+      from: '007',
+      to: '008',
+      callId: "4991155921769858278-#{id}",
+      cause: 'busy'
+    }
+    Net::HTTP.post_form(url, params.merge(event: 'newCall'))
+    Net::HTTP.post_form(url, params.merge(event: 'hangup'))
+
+    # ...for e164 number
+    params = {
+      direction: 'in',
+      from: '4930609854180',
+      to: '4930609811111',
+      callId: "4991155921769858278-#{id.next}",
+      cause: 'busy'
+    }
+    Net::HTTP.post_form(url, params.merge(event: 'newCall'))
+    Net::HTTP.post_form(url, params.merge(event: 'hangup'))
+
+    # view caller log
+    click(css: 'a[href="#cti"]')
+
+    # assertion: private network numbers appear verbatim
+    match(
+      css: '.js-callerLog',
+      value: '007',
+    )
+
+    match(
+      css: '.js-callerLog',
+      value: '008',
+    )
+
+    # assertion: E164 numbers appear prettified
+    match(
+      css: '.js-callerLog',
+      value: '+49 30 609854180',
+    )
+
+    match(
+      css: '.js-callerLog',
+      value: '+49 30 609811111',
+    )
+  end
+end

+ 3 - 5
test/browser/integration_sipgate_notify_not_clearing_on_leftside_test.rb → test/browser/integration_sipgate_test.rb

@@ -1,9 +1,8 @@
 require 'browser_test_helper'
 
-# Regression test for #2017
-
-class IntegrationSipgateNotifyNotClearingOnLeftsideTest < TestCase
-  def test_notify_badge
+class IntegrationSipgateTest < TestCase
+  # Regression test for #2017
+  def test_nav_menu_notification_badge_clears
     id = rand(99_999_999)
 
     @browser = browser_instance
@@ -29,7 +28,6 @@ class IntegrationSipgateNotifyNotClearingOnLeftsideTest < TestCase
     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'))

Some files were not shown because too many files changed in this diff