Skip to content

Commit 8a22b14

Browse files
committed
add verify controls
1 parent dae7232 commit 8a22b14

File tree

15 files changed

+373
-31
lines changed

15 files changed

+373
-31
lines changed

http_client/src/vonage_http_client/auth.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ def sign_params(self, params: dict) -> str:
9696

9797
if not params.get('timestamp'):
9898
params['timestamp'] = int(time())
99-
print(params['timestamp'])
10099

101100
for key in sorted(params):
102101
value = params[key]

http_client/src/vonage_http_client/http_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def _parse_response(self, response: Response) -> Union[dict, None]:
221221
f'Response received from {response.url} with status code: {response.status_code}; headers: {response.headers}'
222222
)
223223
self._last_response = response
224-
224+
print(response.content)
225225
content_type = response.headers['Content-Type'].split(';', 1)[0]
226226
if 200 <= response.status_code < 300:
227227
if response.status_code == 204:

number_insight_v2/tests/test_number_insight_v2.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ def test_ni2_fraud_score_only():
7272
assert response.sim_swap is None
7373

7474
clear_response = asdict(response, dict_factory=remove_none_values)
75-
print(clear_response)
7675
assert 'fraud_score' in clear_response
7776
assert 'sim_swap' not in clear_response
7877

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import List, Literal, Optional
22

33
from pydantic import BaseModel
44

@@ -17,17 +17,40 @@ class CheckCodeResponse(BaseModel):
1717
estimated_price_messages_sent: Optional[str] = None
1818

1919

20-
# class MessageResponse(BaseModel):
21-
# to: str
22-
# message_id: str = Field(..., validation_alias='message-id')
23-
# status: str
24-
# remaining_balance: str = Field(..., validation_alias='remaining-balance')
25-
# message_price: str = Field(..., validation_alias='message-price')
26-
# network: str
27-
# client_ref: Optional[str] = Field(None, validation_alias='client-ref')
28-
# account_ref: Optional[str] = Field(None, validation_alias='account-ref')
20+
class Check(BaseModel):
21+
date_received: Optional[str] = None
22+
code: Optional[str] = None
23+
status: Optional[str] = None
24+
ip_address: Optional[str] = None
25+
26+
27+
class Event(BaseModel):
28+
type: Optional[str] = None
29+
id: Optional[str] = None
30+
31+
32+
class VerifyStatus(BaseModel):
33+
request_id: Optional[str] = None
34+
account_id: Optional[str] = None
35+
status: Optional[str] = None
36+
number: Optional[str] = None
37+
price: Optional[str] = None
38+
currency: Optional[str] = None
39+
sender_id: Optional[str] = None
40+
date_submitted: Optional[str] = None
41+
date_finalized: Optional[str] = None
42+
first_event_date: Optional[str] = None
43+
last_event_date: Optional[str] = None
44+
checks: Optional[List[Check]] = None
45+
events: Optional[List[Event]] = None
46+
estimated_price_messages_sent: Optional[str] = None
47+
48+
49+
class VerifyControlStatus(BaseModel):
50+
status: str
51+
command: str
2952

3053

31-
# class SmsResponse(BaseModel):
32-
# message_count: str = Field(..., validation_alias='message-count')
33-
# messages: List[MessageResponse]
54+
class NetworkUnblockStatus(BaseModel):
55+
network: str
56+
unblocked_until: str

verify/src/vonage_verify/verify.py

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
from pydantic import validate_call
1+
import re
2+
from typing import List, Optional, Union
3+
from pydantic import Field, validate_call
24
from vonage_http_client.http_client import HttpClient
35

46
from .errors import VerifyError
57
from .requests import BaseVerifyRequest, Psd2Request, VerifyRequest
6-
from .responses import CheckCodeResponse, StartVerificationResponse
8+
from .responses import (
9+
CheckCodeResponse,
10+
NetworkUnblockStatus,
11+
StartVerificationResponse,
12+
VerifyControlStatus,
13+
VerifyStatus,
14+
)
715

816

917
class Verify:
@@ -67,6 +75,85 @@ def check_code(self, request_id: str, code: str) -> CheckCodeResponse:
6775
self._check_for_error(response)
6876
return CheckCodeResponse(**response)
6977

78+
@validate_call
79+
def search(
80+
self, request: Union[str, List[str]]
81+
) -> Union[VerifyStatus, List[VerifyStatus]]:
82+
"""Search for past or current verification requests.
83+
84+
Args:
85+
request (str | list[str]): The request ID, or a list of request IDs.
86+
87+
Returns:
88+
Union[VerifyStatus, List[VerifyStatus]]: Either the response object
89+
containing the verification result, or a list of response objects.
90+
"""
91+
params = {}
92+
if type(request) == str:
93+
params['request_id'] = request
94+
elif type(request) == list:
95+
params['request_ids'] = request
96+
97+
response = self._http_client.get(
98+
self._http_client.api_host, '/verify/search/json', params, self._auth_type
99+
)
100+
101+
if 'verification_requests' in response:
102+
parsed_response = []
103+
for verification_request in response['verification_requests']:
104+
parsed_response.append(VerifyStatus(**verification_request))
105+
return parsed_response
106+
elif 'error_text' in response:
107+
error_message = f'Error with the following details: {response}'
108+
raise VerifyError(error_message)
109+
else:
110+
parsed_response = VerifyStatus(**response)
111+
return parsed_response
112+
113+
@validate_call
114+
def cancel_verification(self, request_id: str) -> VerifyControlStatus:
115+
"""Cancel a verification request.
116+
117+
Args:
118+
request_id (str): The request ID.
119+
120+
Returns:
121+
VerifyControlStatus: The response object containing details of the submitted
122+
verification control.
123+
"""
124+
response = self._http_client.post(
125+
self._http_client.api_host,
126+
'/verify/control/json',
127+
{'request_id': request_id, 'cmd': 'cancel'},
128+
self._auth_type,
129+
self._sent_data_type,
130+
)
131+
self._check_for_error(response)
132+
133+
return VerifyControlStatus(**response)
134+
135+
@validate_call
136+
def trigger_next_event(self, request_id: str) -> VerifyControlStatus:
137+
"""Trigger the next event in the verification process.
138+
139+
Args:
140+
request_id (str): The request ID.
141+
142+
Returns:
143+
VerifyControlStatus: The response object containing details of the submitted
144+
verification control.
145+
"""
146+
response = self._http_client.post(
147+
self._http_client.api_host,
148+
'/verify/control/json',
149+
{'request_id': request_id, 'cmd': 'trigger_next_event'},
150+
self._auth_type,
151+
self._sent_data_type,
152+
)
153+
self._check_for_error(response)
154+
155+
return VerifyControlStatus(**response)
156+
70157
def _make_verify_request(
71158
self, verify_request: BaseVerifyRequest
72159
) -> StartVerificationResponse:
@@ -84,6 +171,7 @@ def _make_verify_request(
84171
request_path = '/verify/json'
85172
elif type(verify_request) == Psd2Request:
86173
request_path = '/verify/psd2/json'
174+
87175
response = self._http_client.post(
88176
self._http_client.api_host,
89177
request_path,
@@ -92,24 +180,21 @@ def _make_verify_request(
92180
self._sent_data_type,
93181
)
94182
self._check_for_error(response)
95-
parsed_response = StartVerificationResponse(**response)
96183

97-
return parsed_response
184+
return StartVerificationResponse(**response)
98185

99186
def _check_for_error(self, response: dict) -> None:
100187
"""Check for error in the response.
101188
102-
This method checks if the response contains an error and raises a VerifyError if an error is found.
189+
This method checks if the response contains a non-zero status code
190+
and raises a VerifyError if this is found.
103191
104192
Args:
105193
response (dict): The response object.
106194
107195
Raises:
108196
VerifyError: If an error is found in the response.
109197
"""
110-
print(self._http_client.last_request.body)
111198
if int(response['status']) != 0:
112-
error_message = f'Error with Vonage status code {response["status"]}: {response["error_text"]}.'
113-
if 'network' in response:
114-
error_message += f' Network ID: {response["network"]}'
199+
error_message = f'Error with the following details: {response}'
115200
raise VerifyError(error_message)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"status": "0",
3+
"command": "cancel"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"status": "6",
3+
"error_text": "The requestId 'cc121958d8fb4368aa3bb762bb9a0f75' does not exist or its no longer active."
4+
}

verify/tests/data/check_code.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"request_id": "c5037cb8b47449158ed6611afde58990",
3+
"status": "0",
4+
"event_id": "390f7296-aeff-45ba-8931-84a13f3f76d7",
5+
"price": "0.05000000",
6+
"currency": "EUR",
7+
"estimated_price_messages_sent": "0.04675"
8+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"request_id": "cc121958d8fb4368aa3bb762bb9a0f74",
3+
"status": "16",
4+
"error_text": "The code provided does not match the expected value"
5+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"request_id": "cc121958d8fb4368aa3bb762bb9a0f74",
3+
"account_id": "abcdef01",
4+
"status": "EXPIRED",
5+
"number": "1234567890",
6+
"price": "0",
7+
"currency": "EUR",
8+
"sender_id": "Acme Inc.",
9+
"date_submitted": "2024-04-03 02:22:37",
10+
"date_finalized": "2024-04-03 02:27:38",
11+
"first_event_date": "2024-04-03 02:22:37",
12+
"last_event_date": "2024-04-03 02:24:38",
13+
"checks": [
14+
{
15+
"date_received": "2024-04-03 02:23:04",
16+
"code": "1234",
17+
"status": "INVALID",
18+
"ip_address": ""
19+
}
20+
],
21+
"events": [
22+
{
23+
"type": "sms",
24+
"id": "23f3a13d-6d03-4262-8f4d-67f12a56e1c8"
25+
},
26+
{
27+
"type": "sms",
28+
"id": "09ef3984-3f62-453d-8f9c-1a161b373dba"
29+
}
30+
],
31+
"estimated_price_messages_sent": "0.09350"
32+
}

0 commit comments

Comments
 (0)