Skip to content

Commit b357623

Browse files
authored
Refactor Telephony API Wrapper to Fix Parameter Handling (#286)
* Refactor `get_params_from_kwargs` to handle kwargs as a dictionary and add tests for telephony log retrieval with various parameters * Improve get_telephony_log method for API v2 support and clean up Telephony module * rename tests * Fix sort arg for v2, update v1 and v2 tests, default to ms for v2 and seconds for v1. * readd deleted files * add new line * update type hints for get_telephony_log parameters * Remove VALID_TELEPHONY_V2_REQUEST_PARAMS global from admin.py and update API path formatting
1 parent 46a8cc7 commit b357623

3 files changed

Lines changed: 110 additions & 8 deletions

File tree

duo_client/admin.py

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,6 @@
182182
from datetime import datetime, timedelta, timezone
183183

184184
from . import Accounts, client
185-
from .logs.telephony import Telephony
186-
187185
USER_STATUS_ACTIVE = "active"
188186
USER_STATUS_BYPASS = "bypass"
189187
USER_STATUS_DISABLED = "disabled"
@@ -629,12 +627,21 @@ def get_activity_logs(self, **kwargs):
629627
row['host'] = self.host
630628
return response
631629

632-
def get_telephony_log(self, mintime=0, api_version=1, **kwargs):
630+
def get_telephony_log(self, mintime: int = 0, api_version: int = 1, maxtime: Optional[int] = 0,
631+
limit: Optional[int] = 100, sort: Optional[str] = 'desc',
632+
next_offset: Optional[str] = None, account_id = None,
633+
filters = None, **kwargs):
633634
"""
634635
Returns telephony log events.
635636
636637
mintime - Fetch events only >= mintime (to avoid duplicate
637638
records that have already been fetched)
639+
maxtime - Fetch events only <= maxtime. (API Version 2 only)
640+
limit - Number of results to limit to, default 100, max 1000. (API Version 2 only)
641+
sort - Sort order to be applied, default 'desc'. (API Version 2 only)
642+
next_offset - Used to grab the next set of results from a previous response. (API Version 2 only)
643+
account_id - Filter by account_id. (API Version 2 only) Type undocumented.
644+
filters - Filter by filters. (API Version 2 only) Type undocumented.
638645
api_version - The API version of the handler to use.
639646
Currently, the default api version is v1, but the v1 API
640647
will be deprecated in a future version of the Duo Admin API.
@@ -683,11 +690,42 @@ def get_telephony_log(self, mintime=0, api_version=1, **kwargs):
683690

684691
if api_version not in [1,2]:
685692
raise ValueError("Invalid API Version")
693+
694+
params = {}
686695

687-
if api_version == 2:
688-
return Telephony.get_telephony_logs_v2(self.json_api_call, self.host, **kwargs)
689-
return Telephony.get_telephony_logs_v1(self.json_api_call, self.host, mintime=mintime)
696+
today = datetime.now(tz=timezone.utc)
697+
# If mintime is not provided, the script defaults it to 180 days in past
698+
mintime = int((today - timedelta(days=180)).timestamp() * (1000 if api_version == 2 else 1)) if not mintime else mintime
699+
params["mintime"] = f"{int(mintime)}"
700+
701+
if api_version == 2: # Add additional parameters for API Version 2
702+
if limit > 1000:
703+
limit = 1000 # Limit is capped at 1000
704+
params["limit"] = f"{int(limit)}"
705+
706+
params["sort"] = 'ts:desc' if sort.lower() == 'desc' else 'ts:asc'
707+
# if maxtime is not provided, the script defaults it to now
708+
maxtime = int(today.timestamp() * 1000) - 120 if not maxtime else maxtime
709+
params["maxtime"] = f"{int(maxtime)}"
710+
if next_offset:
711+
params["next_offset"] = next_offset
712+
if account_id:
713+
params["account_id"] = account_id
714+
if filters:
715+
params["filters"] = filters
716+
response = self.json_api_call("GET", '/admin/v{}/logs/telephony'.format(api_version), params)
690717

718+
if api_version == 1:
719+
for row in response:
720+
row["eventtype"] = "telephony"
721+
row["host"] = self.host
722+
else:
723+
for row in response["items"]:
724+
row["eventtype"] = "telephony"
725+
row["host"] = self.host
726+
727+
return response
728+
691729
def get_users_iterator(self):
692730
"""
693731
Returns iterator of user objects.
@@ -3804,4 +3842,4 @@ def set_telephony_credits(self, credits):
38043842
}
38053843
return self.json_api_call('POST',
38063844
'/admin/v1/billing/telephony_credits',
3807-
params)
3845+
params)

examples/Admin/log_examples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def get_next_arg(prompt, default=None):
7979
]
8080
)
8181
if log_type == "telephony_v2":
82-
telephony_logs = admin_api.get_telephony_log(api_version=2, kwargs=params)
82+
telephony_logs = admin_api.get_telephony_log(api_version=2, **params)
8383
reporter.writerow(("telephony_id", "txid", "credits", "context", "phone", "type"))
8484

8585
for log in telephony_logs["items"]:

tests/admin/test_telephony.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,74 @@ def test_get_telephony_logs_v2_no_args(self):
3333
self.assertEqual(uri, "/admin/v2/logs/telephony")
3434
self.assertEqual(param_dict["mintime"], [expected_mintime])
3535
self.assertEqual(param_dict["maxtime"], [expected_maxtime])
36+
self.assertAlmostEqual(param_dict["sort"], ["ts:desc"])
37+
self.assertEqual(param_dict["limit"], ["100"])
38+
39+
@freeze_time("2022-10-01")
40+
def test_get_telephony_logs_v2_with_args(self):
41+
mintime = datetime(2022, 9, 1, 0, 0, 0, tzinfo=pytz.utc)
42+
expected_mintime = str(int(mintime.timestamp() * 1000))
43+
maxtime = datetime(2022, 10, 1, 0, 0, 0, tzinfo=pytz.utc)
44+
expected_maxtime = str(int(maxtime.timestamp() * 1000) - 120)
45+
params = {"mintime": expected_mintime, "sort": "asc", "limit": 900}
46+
response = self.items_response_client.get_telephony_log(api_version=2,
47+
**params)
48+
uri, args = response["uri"].split("?")
49+
param_dict = util.params_to_dict(args)
50+
self.assertEqual(response["method"], "GET")
51+
self.assertEqual(uri, "/admin/v2/logs/telephony")
52+
self.assertEqual(param_dict["mintime"], [expected_mintime])
53+
self.assertEqual(param_dict["maxtime"], [expected_maxtime])
54+
self.assertEqual(param_dict["sort"], ["ts:asc"])
55+
self.assertEqual(param_dict["limit"], ["900"])
56+
57+
@freeze_time("2022-10-01")
58+
def test_get_telephony_logs_v2_with_unsupported_args(self):
59+
params = {
60+
"unsupported": "argument",
61+
"non_existent": "argument"
62+
}
63+
response = self.items_response_client.get_telephony_log(api_version=2,
64+
**params)
65+
uri, args = response["uri"].split("?")
66+
param_dict = util.params_to_dict(args)
67+
self.assertEqual(response["method"], "GET")
68+
self.assertEqual(uri, "/admin/v2/logs/telephony")
69+
self.assertNotIn("unsupported", param_dict)
70+
self.assertNotIn("non_existent", param_dict)
3671

3772
@freeze_time("2022-10-01")
3873
def test_get_telephony_logs_v1_no_args(self):
3974
response = self.client_list.get_telephony_log()
4075
uri, args = response[0]["uri"].split("?")
4176
self.assertEqual(response[0]["method"], "GET")
4277
self.assertEqual(uri, "/admin/v1/logs/telephony")
78+
79+
@freeze_time("2022-10-01")
80+
def test_get_telephony_logs_v1_with_args(self):
81+
freezed_time = datetime(2022, 9, 1, 0, 0, 0, tzinfo=pytz.utc)
82+
expected_mintime = str(
83+
int((freezed_time - timedelta(days=180)).timestamp())
84+
)
85+
response = self.client_list.get_telephony_log(mintime=expected_mintime)
86+
uri, args = response[0]["uri"].split("?")
87+
param_dict = util.params_to_dict(args)
88+
self.assertEqual(response[0]["method"], "GET")
89+
self.assertEqual(uri, "/admin/v1/logs/telephony")
90+
self.assertEqual(param_dict["mintime"], [expected_mintime])
91+
92+
@freeze_time("2022-10-01")
93+
def test_get_telephony_logs_v1_ignore_v2_args(self):
94+
freezed_time = datetime(2022, 9, 1, 0, 0, 0, tzinfo=pytz.utc)
95+
expected_mintime = str(
96+
int((freezed_time - timedelta(days=180)).timestamp())
97+
)
98+
params = {"mintime": expected_mintime, "limit": 20, "sort": "ts:asc"}
99+
response = self.client_list.get_telephony_log(**params)
100+
uri, args = response[0]["uri"].split("?")
101+
param_dict = util.params_to_dict(args)
102+
self.assertEqual(response[0]["method"], "GET")
103+
self.assertEqual(uri, "/admin/v1/logs/telephony")
104+
self.assertEqual(param_dict["mintime"], [expected_mintime])
105+
self.assertNotIn(param_dict["limit"], ["limit"])
106+
self.assertNotIn(param_dict["sort"], ["sort"])

0 commit comments

Comments
 (0)