Skip to content

Commit 1b0d40a

Browse files
Pull request #14: Feature/EOA-2074 Update functionality
Merge in SDK/python_telesign_enterprise from feature/EOA-2074-Update-functionality to developer * commit '15a44820c91d3a662d2848d2634112eaa023062b': set basic_auth param consolidate both retrieve and update functionality update comments validate conflict update the release updated comments addedupdate functionlity
2 parents 5c5feee + 15a4482 commit 1b0d40a

File tree

7 files changed

+203
-10
lines changed

7 files changed

+203
-10
lines changed

RELEASE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
2.3.0
2-
- Created OmniVerify class for adding retrieve verification process functionality
2+
- Created OmniVerify class for adding retrieve and update verification process functionality
33

44
- Moved the createVerificationProcess method from the VerifyClient class to the new OmniVerify class,
55
consolidating omnichannel verification responsibilities in one place
66

7-
- Added unit and integration tests to telesignenterpise.test folder
7+
- Added unit and integration tests
88

99
2.2.2
1010
- Added tracking to requests

examples/omni_verify/1_retrieve_verification_process.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44

55
customer_id = "FFFFFFFF-EEEE-DDDD-1234-AB1234567890"
6-
api_key = "EXAMPLE----TE8sTgg45yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
6+
api_key = "ABC12345yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
77

88
phone_number = input("Please enter the phone number (with country code, digits only): ").strip()
99
if not phone_number.isdigit():
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from __future__ import print_function
2+
from telesignenterprise.omniverify import OmniVerify
3+
import json
4+
5+
customer_id = "FFFFFFFF-EEEE-DDDD-1234-AB1234567890"
6+
api_key = "ABC12345yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
7+
8+
phone_number = input("Please enter the phone number (with country code, digits only): ").strip()
9+
if not phone_number.isdigit():
10+
print("Error: phone number must contain digits only.")
11+
exit(1)
12+
13+
omniverify = OmniVerify(customer_id, api_key)
14+
15+
# Create the verification process
16+
create_params = {
17+
"verification_policy": [{"method": "sms"}]
18+
}
19+
create_response = omniverify.createVerificationProcess(phone_number, create_params)
20+
21+
if create_response.ok:
22+
reference_id = create_response.json.get("reference_id")
23+
print("Verification process created successfully.")
24+
print("Reference ID:", reference_id)
25+
else:
26+
print("Failed to create verification process.")
27+
print("Status code:", create_response.status_code)
28+
print("Response:", create_response.json)
29+
exit(1)
30+
31+
# Retrieve the verification process
32+
retrieve_response = omniverify.getVerificationProcess(reference_id)
33+
if retrieve_response.ok:
34+
print("Verification process retrieved successfully.")
35+
print(json.dumps(retrieve_response.json, indent=4))
36+
else:
37+
print("Failed to retrieve verification process.")
38+
print("Status code:", retrieve_response.status_code)
39+
print("Response:", retrieve_response.json)
40+
exit(1)
41+
42+
# Prompt for OTP (security factor) and update the verification process
43+
security_factor = input("Please enter the OTP (security factor) to finalize the verification: ").strip()
44+
45+
update_params = {
46+
"action": "finalize",
47+
"security_factor": security_factor
48+
}
49+
use_basic_auth = True
50+
update_response = omniverify.updateVerificationProcess(reference_id, update_params, use_basic_auth=use_basic_auth)
51+
52+
if update_response.ok:
53+
print("Verification process updated successfully.")
54+
response_json = update_response.json() if callable(update_response.json) else update_response.json
55+
print("Response:")
56+
print(json.dumps(response_json, indent=4))
57+
else:
58+
print("Failed to update verification process.")
59+
print("Status code:", update_response.status_code)
60+
response_json = update_response.json() if callable(update_response.json) else update_response.json
61+
print("Response:", response_json)

telesignenterprise/omniverify.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
from telesignenterprise.constants import SOURCE_SDK
55
import telesignenterprise
66
import telesign
7+
import requests, json, base64
78

89
BASE_URL_VERIFY_API = "https://verify.telesign.com"
910
PATH_VERIFICATION_CREATE = "/verification"
1011
PATH_VERIFICATION_RETRIEVE = "/verification/{reference_id}"
12+
PATH_VERIFICATION_UPDATE = "/verification/{reference_id}/state"
1113

1214
class OmniVerify(RestClient):
1315
"""
@@ -48,11 +50,51 @@ def getVerificationProcess(self, reference_id, params={}):
4850
"""
4951
Retrieve details about the specified verification process.
5052
53+
See https://developer.telesign.com/enterprise/reference/getverificationprocess for detailed API documentation.
54+
5155
:param reference_id: The unique identifier of the verification process.
5256
:param params: Optional query parameters as a dictionary.
5357
:return: Response object from the GET request.
5458
"""
5559
endpoint = PATH_VERIFICATION_RETRIEVE.format(reference_id=reference_id)
5660
headers = {"Content-Type": "application/json", "Accept": "application/json"}
5761

58-
return self.get(endpoint, json_fields=params, headers=headers)
62+
return self.get(endpoint, json_fields=params, headers=headers)
63+
64+
def updateVerificationProcess(self, reference_id, params, use_basic_auth=False):
65+
"""
66+
Update a verification process.
67+
68+
See https://developer.telesign.com/enterprise/reference/updateverificationprocess for detailed API documentation.
69+
70+
:param reference_id: The unique identifier of the verification process.
71+
:param params: Dictionary of parameters for the update (must include 'action' and 'security_factor').
72+
:param use_basic_auth: Boolean indicating whether to use manual Basic Auth.
73+
:return: Response object.
74+
"""
75+
endpoint_path = PATH_VERIFICATION_UPDATE.format(reference_id=reference_id)
76+
77+
if use_basic_auth:
78+
endpoint = self.api_host.rstrip('/') + endpoint_path
79+
80+
json_body = json.dumps(params)
81+
82+
auth_str = f"{self.customer_id}:{self.api_key}"
83+
auth_bytes = auth_str.encode('utf-8')
84+
auth_b64 = base64.b64encode(auth_bytes).decode('utf-8')
85+
headers = {
86+
"Authorization": f"Basic {auth_b64}",
87+
"Content-Type": "application/json",
88+
"Accept": "application/json"
89+
}
90+
response = requests.patch(endpoint, data=json_body, headers=headers)
91+
return type('Response', (), {
92+
'status_code': response.status_code,
93+
'headers': response.headers,
94+
'body': response.text,
95+
'ok': response.ok,
96+
'json': response.json
97+
})()
98+
else:
99+
headers = {"Content-Type": "application/json", "Accept": "application/json"}
100+
return self.patch(endpoint_path, json_fields=params, headers=headers)

telesignenterprise/verify.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ def __init__(
4040
self.omniverify = OmniVerify(customer_id, api_key)
4141

4242
def createVerificationProcess(self, phone_number, params={}):
43-
"""
44-
Proxy method to OmniVerify.createVerificationProcess for streamlined integration.
45-
"""
43+
4644
return self.omniverify.createVerificationProcess(phone_number, params)
4745

4846
def sms(self, phone_number, **params):

tests/test_integration_omniverify.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# Replace with actual credentials for successful test response
55
CUSTOMER_ID = "FFFFFFFF-EEEE-DDDD-1234-AB1234567890"
6-
API_KEY = "EXAMPLE----TE8sTgg45yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
6+
API_KEY = "ABC12345yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
77

88
@pytest.fixture(scope="module")
99
def omniverify():
@@ -30,3 +30,44 @@ def test_create_and_retrieve_verification_process(omniverify):
3030

3131
data = retrieve_response.json
3232
assert "reference_id" in data and data["reference_id"] == reference_id
33+
34+
def test_create_update_and_retrieve_verification_process(omniverify):
35+
phone_number = "11234567890" # Replace with a valid test phone number including country code
36+
37+
# Create verification process
38+
create_params = {
39+
"verification_policy": [{"method": "sms"}]
40+
}
41+
create_response = omniverify.createVerificationProcess(phone_number, create_params)
42+
assert create_response.ok, f"Failed to create verification process: {create_response.json}"
43+
reference_id = create_response.json.get("reference_id")
44+
assert reference_id and len(reference_id) == 32, "Invalid reference_id returned"
45+
46+
# Simulate user entering the OTP (replace '123456' with an actual OTP for a successful response)
47+
otp_code = "123456"
48+
update_params = {
49+
"action": "finalize",
50+
"security_factor": otp_code
51+
}
52+
# Test both SDK-internal and manual Basic Auth PATCH
53+
for use_basic_auth in (False, True):
54+
update_response = omniverify.updateVerificationProcess(reference_id, update_params, use_basic_auth=use_basic_auth)
55+
# Acceptable error codes: 400 (bad request), 401 (unauthorized), 3904/3909 (Telesign verification errors: Rate Eimit Exceeded/Invalid code entered), 3400 (Telesign not authorized)
56+
allowed_status_codes = (400, 401, 3904, 3909)
57+
allowed_telesign_codes = (3400)
58+
telesign_code = (
59+
update_response.json.get("status", {}).get("code")
60+
if update_response.json and isinstance(update_response.json, dict)
61+
else None
62+
)
63+
assert (
64+
update_response.ok
65+
or update_response.status_code in allowed_status_codes
66+
or telesign_code in allowed_telesign_codes
67+
), f"Unexpected update response: {update_response.json}"
68+
69+
# Retrieve verification process details
70+
retrieve_response = omniverify.getVerificationProcess(reference_id)
71+
assert retrieve_response.ok, f"Failed to retrieve verification process: {retrieve_response.json}"
72+
data = retrieve_response.json
73+
assert "reference_id" in data and data["reference_id"] == reference_id

tests/test_omniverify.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@pytest.fixture
66
def omniverify():
77
customer_id = "FFFFFFFF-EEEE-DDDD-1234-AB1234567890"
8-
api_key = "EXAMPLE----TE8sTgg45yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
8+
api_key = "ABC12345yusumoN6BYsBVkh+yRJ5czgsnCehZaOYldPJdmFh6NeX8kunZ2zU1YWaUw/0wV6xfw=="
99
return OmniVerify(customer_id, api_key)
1010

1111
def test_create_verification_process_success(omniverify):
@@ -67,4 +67,55 @@ def test_get_verification_process_invalid_reference_id(omniverify):
6767
assert called_url == f"/verification/{invalid_reference_id}"
6868
assert not response.ok
6969
assert response.status_code == 400
70-
assert response.json["status"]["code"] == 3400
70+
assert response.json["status"]["code"] == 3400
71+
72+
def test_update_verification_process_success(omniverify):
73+
reference_id = "a" * 32
74+
params = {
75+
"action": "finalize",
76+
"security_factor": "123456"
77+
}
78+
79+
with patch.object(OmniVerify, 'patch') as mock_patch:
80+
mock_response = MagicMock()
81+
mock_response.ok = True
82+
mock_response.json = {
83+
"status": {"code": 3900, "description": "Verified"},
84+
"reference_id": reference_id
85+
}
86+
mock_patch.return_value = mock_response
87+
88+
response = omniverify.updateVerificationProcess(reference_id, params)
89+
90+
mock_patch.assert_called_once()
91+
called_url = mock_patch.call_args[0][0]
92+
called_json = mock_patch.call_args[1]['json_fields']
93+
94+
assert called_url == f"/verification/{reference_id}/state"
95+
assert called_json["action"] == "finalize"
96+
assert called_json["security_factor"] == "123456"
97+
assert response.ok
98+
assert response.json["status"]["code"] == 3900
99+
100+
def test_update_verification_process_invalid_code(omniverify):
101+
reference_id = "a" * 32
102+
params = {
103+
"action": "finalize",
104+
"security_factor": "wrongcode"
105+
}
106+
107+
with patch.object(OmniVerify, 'patch') as mock_patch:
108+
mock_response = MagicMock()
109+
mock_response.ok = False
110+
mock_response.status_code = 400
111+
mock_response.json = {
112+
"status": {"code": 3904, "description": "Verification Failed"}
113+
}
114+
mock_patch.return_value = mock_response
115+
116+
response = omniverify.updateVerificationProcess(reference_id, params)
117+
118+
mock_patch.assert_called_once()
119+
assert not response.ok
120+
assert response.status_code == 400
121+
assert response.json["status"]["code"] == 3904

0 commit comments

Comments
 (0)