Skip to content

Commit

Permalink
Merge pull request #490 from wazo-platform/WAZO-3942-change-callerids…
Browse files Browse the repository at this point in the history
…-outgoing-source

WAZO 3942 change callerids outgoing source

Reviewed-by: rbienvenu0 <[email protected]>
Reviewed-by: Charles <[email protected]>
  • Loading branch information
wazo-community-zuul[bot] authored Nov 14, 2024
2 parents 5da04e5 + ff784ac commit d1de963
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 31 deletions.
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Depends:
python3-requests,
python3-werkzeug,
python3-tz,
python3-phonenumbers,
wazo-auth-client-python3,
wazo-provd-client-python3,
wazo-bus-python3,
Expand Down
61 changes: 35 additions & 26 deletions integration_tests/suite/base/test_user_callerid.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,31 @@ def test_list_when_no_incall(user):
assert_that(response.total, equal_to(1))


@fixtures.extension(exten='5555551234', context=INCALL_CONTEXT)
@fixtures.incall()
@fixtures.extension(exten='5555556789', context=INCALL_CONTEXT)
@fixtures.incall()
@fixtures.user()
def test_list_with_associated_type(extension1, incall1, extension2, incall2, user):
def test_list_with_associated_type(extension, incall, user):
destination = {'type': 'user', 'user_id': user['id']}
confd.incalls(incall1['id']).put(destination=destination).assert_updated()
confd.incalls(incall2['id']).put(destination=destination).assert_updated()
confd.incalls(incall['id']).put(destination=destination).assert_updated()

with a.incall_extension(incall1, extension1):
with a.incall_extension(incall2, extension2):
response = confd.users(user['uuid']).callerids.outgoing.get()
with a.incall_extension(incall, extension):
response = confd.users(user['uuid']).callerids.outgoing.get()

expected = [
{'type': 'main', 'number': '5555551234'},
{'type': 'associated', 'number': '5555551234'},
{'type': 'associated', 'number': '5555556789'},
{'type': 'anonymous'},
]
assert_that(response.items, contains_inanyorder(*expected))
assert_that(response.total, equal_to(4))
assert_that(response.total, equal_to(2))


@fixtures.extension(exten='5555551234', context=INCALL_CONTEXT)
@fixtures.incall(destination={'type': 'custom', 'command': 'Playback(Welcome)'})
@fixtures.phone_number(main=True, number='5555551234')
@fixtures.extension(exten='5555556789', context=INCALL_CONTEXT)
@fixtures.incall(destination={'type': 'custom', 'command': 'Playback(IGNORED)'})
@fixtures.user()
def test_list_with_main_type(extension1, incall1, extension2, incall2, user):
with a.incall_extension(incall1, extension1):
with a.incall_extension(incall2, extension2):
response = confd.users(user['uuid']).callerids.outgoing.get()
def test_list_with_main_type(phone_number, extension, incall, user):
with a.incall_extension(incall, extension):
response = confd.users(user['uuid']).callerids.outgoing.get()

# The first created is the main and other are ignored
expected = [
Expand All @@ -68,26 +60,43 @@ def test_list_with_main_type(extension1, incall1, extension2, incall2, user):
assert_that(response.total, equal_to(2))


@fixtures.extension(exten='5555551234', context=INCALL_CONTEXT)
@fixtures.incall(destination={'type': 'custom', 'command': 'Playback(Welcome)'})
@fixtures.extension(exten='5555556789', context=INCALL_CONTEXT)
@fixtures.phone_number(shared=True, number='5555551234')
@fixtures.user()
def test_list_with_shared(phone_number, user):
response = confd.users(user['uuid']).callerids.outgoing.get()

# The first created is the main and other are ignored
expected = [
{'type': 'shared', 'number': '5555551234'},
{'type': 'anonymous'},
]
assert_that(response.items, contains_inanyorder(*expected))
assert_that(response.total, equal_to(2))


@fixtures.phone_number(main=True, number='5555551234')
@fixtures.phone_number(shared=True, number='5555551235')
@fixtures.phone_number(shared=True, number='5555551236')
@fixtures.extension(exten='5555551235', context=INCALL_CONTEXT)
@fixtures.incall()
@fixtures.user()
def test_list_with_all_type(main_extension, main_incall, extension, incall, user):
def test_list_with_all_type(
main_number, shared_number1, shared_number2, extension, incall, user
):
destination = {'type': 'user', 'user_id': user['id']}
confd.incalls(incall['id']).put(destination=destination).assert_updated()

with a.incall_extension(main_incall, main_extension):
with a.incall_extension(incall, extension):
response = confd.users(user['uuid']).callerids.outgoing.get()
with a.incall_extension(incall, extension):
response = confd.users(user['uuid']).callerids.outgoing.get()

expected = [
{'type': 'main', 'number': '5555551234'},
{'type': 'associated', 'number': '5555556789'},
{'type': 'associated', 'number': '5555551235'},
{'type': 'shared', 'number': '5555551236'},
{'type': 'anonymous'},
]
assert_that(response.items, contains_inanyorder(*expected))
assert_that(response.total, equal_to(3))
assert_that(response.total, equal_to(4))


@fixtures.user(wazo_tenant=MAIN_TENANT)
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ sqlalchemy-utils==0.36.8 # from xivo-dao
stevedore==4.0.2
unidecode==1.2.0 # from xivo-dao
werkzeug==1.0.1
phonenumbers==8.12.1
51 changes: 46 additions & 5 deletions wazo_confd/plugins/user_callerid/service.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,68 @@
# Copyright 2024 The Wazo Authors (see the AUTHORS file)
# SPDX-License-Identifier: GPL-3.0-or-later

import phonenumbers
from dataclasses import dataclass

from xivo_dao.resources.user import dao as user_dao
from xivo_dao.resources.incall import dao as incall_dao
from xivo_dao.resources.phone_number import dao as phone_number_dao

from .types import CallerIDType


class CallerIDAnonymous:
type = 'anonymous'


@dataclass()
class CallerID:
type: CallerIDType
number: str


def same_phone_number(number1: str, number2: str) -> bool:
'''
compare two strings semantically as phone numbers
'''
result = phonenumbers.is_number_match(number1, number2)
return result in (
phonenumbers.MatchType.EXACT_MATCH,
phonenumbers.MatchType.NSN_MATCH,
)


class UserCallerIDService:
def __init__(self, user_dao, incall_dao):
def __init__(self, user_dao, incall_dao, phone_number_dao):
self.user_dao = user_dao
self.incall_dao = incall_dao
self.phone_number_dao = phone_number_dao

def search(self, user_id, tenant_uuid, parameters):
callerids = []
if main_callerid := self.incall_dao.find_main_callerid(tenant_uuid):
callerids.append(main_callerid)
callerids.extend(self.user_dao.list_outgoing_callerid_associated(user_id))
if main_callerid := self.phone_number_dao.find_by(
main=True, tenant_uuids=[tenant_uuid]
):
callerids.append(CallerID(type='main', number=main_callerid.number))

# consider "associated" caller ids from incalls
# as having precedence over shared phone numbers
callerids.extend(
callerid
for callerid in self.user_dao.list_outgoing_callerid_associated(user_id)
if not any(same_phone_number(callerid.number, c.number) for c in callerids)
)
shared_callerids = self.phone_number_dao.find_all_by(
shared=True, main=False, tenant_uuids=[tenant_uuid]
)
callerids.extend(
CallerID(type='shared', number=callerid.number)
for callerid in shared_callerids
if not any(same_phone_number(callerid.number, c.number) for c in callerids)
)
callerids.append(CallerIDAnonymous)
return len(callerids), callerids


def build_service():
return UserCallerIDService(user_dao, incall_dao)
return UserCallerIDService(user_dao, incall_dao, phone_number_dao)
Empty file.
25 changes: 25 additions & 0 deletions wazo_confd/plugins/user_callerid/tests/test_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import unittest

from ..service import same_phone_number


class TestSamePhoneNumber(unittest.TestCase):
def test_exact(self):
numbers = ['1234567890', '11234567890', '+11234567890' '4567890', '911']
for number in numbers:
self.assertTrue(same_phone_number(number, number), number)

def test_actually_different(self):
number1 = '11234567890'
number2 = '11234567891'
self.assertFalse(same_phone_number(number1, number2), (number1, number2))

def test_different_country(self):
number1 = '11234567890'
number2 = '21234567890'
self.assertFalse(same_phone_number(number1, number2), (number1, number2))

def test_different_country_one_e164(self):
number1 = '+11234567890'
number2 = '21234567890'
self.assertFalse(same_phone_number(number1, number2), (number1, number2))
3 changes: 3 additions & 0 deletions wazo_confd/plugins/user_callerid/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from typing import Literal

CallerIDType = Literal['main', 'associated', 'anonymous', 'shared']

0 comments on commit d1de963

Please sign in to comment.