Skip to content

Commit

Permalink
add verify controls
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkahan committed Apr 4, 2024
1 parent dae7232 commit 8a22b14
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 31 deletions.
1 change: 0 additions & 1 deletion http_client/src/vonage_http_client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ def sign_params(self, params: dict) -> str:

if not params.get('timestamp'):
params['timestamp'] = int(time())
print(params['timestamp'])

for key in sorted(params):
value = params[key]
Expand Down
2 changes: 1 addition & 1 deletion http_client/src/vonage_http_client/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def _parse_response(self, response: Response) -> Union[dict, None]:
f'Response received from {response.url} with status code: {response.status_code}; headers: {response.headers}'
)
self._last_response = response

print(response.content)
content_type = response.headers['Content-Type'].split(';', 1)[0]
if 200 <= response.status_code < 300:
if response.status_code == 204:
Expand Down
1 change: 0 additions & 1 deletion number_insight_v2/tests/test_number_insight_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ def test_ni2_fraud_score_only():
assert response.sim_swap is None

clear_response = asdict(response, dict_factory=remove_none_values)
print(clear_response)
assert 'fraud_score' in clear_response
assert 'sim_swap' not in clear_response

Expand Down
49 changes: 36 additions & 13 deletions verify/src/vonage_verify/responses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Literal, Optional

from pydantic import BaseModel

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


# class MessageResponse(BaseModel):
# to: str
# message_id: str = Field(..., validation_alias='message-id')
# status: str
# remaining_balance: str = Field(..., validation_alias='remaining-balance')
# message_price: str = Field(..., validation_alias='message-price')
# network: str
# client_ref: Optional[str] = Field(None, validation_alias='client-ref')
# account_ref: Optional[str] = Field(None, validation_alias='account-ref')
class Check(BaseModel):
date_received: Optional[str] = None
code: Optional[str] = None
status: Optional[str] = None
ip_address: Optional[str] = None


class Event(BaseModel):
type: Optional[str] = None
id: Optional[str] = None


class VerifyStatus(BaseModel):
request_id: Optional[str] = None
account_id: Optional[str] = None
status: Optional[str] = None
number: Optional[str] = None
price: Optional[str] = None
currency: Optional[str] = None
sender_id: Optional[str] = None
date_submitted: Optional[str] = None
date_finalized: Optional[str] = None
first_event_date: Optional[str] = None
last_event_date: Optional[str] = None
checks: Optional[List[Check]] = None
events: Optional[List[Event]] = None
estimated_price_messages_sent: Optional[str] = None


class VerifyControlStatus(BaseModel):
status: str
command: str


# class SmsResponse(BaseModel):
# message_count: str = Field(..., validation_alias='message-count')
# messages: List[MessageResponse]
class NetworkUnblockStatus(BaseModel):
network: str
unblocked_until: str
103 changes: 94 additions & 9 deletions verify/src/vonage_verify/verify.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from pydantic import validate_call
import re
from typing import List, Optional, Union
from pydantic import Field, validate_call
from vonage_http_client.http_client import HttpClient

from .errors import VerifyError
from .requests import BaseVerifyRequest, Psd2Request, VerifyRequest
from .responses import CheckCodeResponse, StartVerificationResponse
from .responses import (
CheckCodeResponse,
NetworkUnblockStatus,
StartVerificationResponse,
VerifyControlStatus,
VerifyStatus,
)


class Verify:
Expand Down Expand Up @@ -67,6 +75,85 @@ def check_code(self, request_id: str, code: str) -> CheckCodeResponse:
self._check_for_error(response)
return CheckCodeResponse(**response)

@validate_call
def search(
self, request: Union[str, List[str]]
) -> Union[VerifyStatus, List[VerifyStatus]]:
"""Search for past or current verification requests.
Args:
request (str | list[str]): The request ID, or a list of request IDs.
Returns:
Union[VerifyStatus, List[VerifyStatus]]: Either the response object
containing the verification result, or a list of response objects.
"""
params = {}
if type(request) == str:
params['request_id'] = request
elif type(request) == list:
params['request_ids'] = request

response = self._http_client.get(
self._http_client.api_host, '/verify/search/json', params, self._auth_type
)

if 'verification_requests' in response:
parsed_response = []
for verification_request in response['verification_requests']:
parsed_response.append(VerifyStatus(**verification_request))
return parsed_response
elif 'error_text' in response:
error_message = f'Error with the following details: {response}'
raise VerifyError(error_message)
else:
parsed_response = VerifyStatus(**response)
return parsed_response

@validate_call
def cancel_verification(self, request_id: str) -> VerifyControlStatus:
"""Cancel a verification request.
Args:
request_id (str): The request ID.
Returns:
VerifyControlStatus: The response object containing details of the submitted
verification control.
"""
response = self._http_client.post(
self._http_client.api_host,
'/verify/control/json',
{'request_id': request_id, 'cmd': 'cancel'},
self._auth_type,
self._sent_data_type,
)
self._check_for_error(response)

return VerifyControlStatus(**response)

@validate_call
def trigger_next_event(self, request_id: str) -> VerifyControlStatus:
"""Trigger the next event in the verification process.
Args:
request_id (str): The request ID.
Returns:
VerifyControlStatus: The response object containing details of the submitted
verification control.
"""
response = self._http_client.post(
self._http_client.api_host,
'/verify/control/json',
{'request_id': request_id, 'cmd': 'trigger_next_event'},
self._auth_type,
self._sent_data_type,
)
self._check_for_error(response)

return VerifyControlStatus(**response)

def _make_verify_request(
self, verify_request: BaseVerifyRequest
) -> StartVerificationResponse:
Expand All @@ -84,6 +171,7 @@ def _make_verify_request(
request_path = '/verify/json'
elif type(verify_request) == Psd2Request:
request_path = '/verify/psd2/json'

response = self._http_client.post(
self._http_client.api_host,
request_path,
Expand All @@ -92,24 +180,21 @@ def _make_verify_request(
self._sent_data_type,
)
self._check_for_error(response)
parsed_response = StartVerificationResponse(**response)

return parsed_response
return StartVerificationResponse(**response)

def _check_for_error(self, response: dict) -> None:
"""Check for error in the response.
This method checks if the response contains an error and raises a VerifyError if an error is found.
This method checks if the response contains a non-zero status code
and raises a VerifyError if this is found.
Args:
response (dict): The response object.
Raises:
VerifyError: If an error is found in the response.
"""
print(self._http_client.last_request.body)
if int(response['status']) != 0:
error_message = f'Error with Vonage status code {response["status"]}: {response["error_text"]}.'
if 'network' in response:
error_message += f' Network ID: {response["network"]}'
error_message = f'Error with the following details: {response}'
raise VerifyError(error_message)
4 changes: 4 additions & 0 deletions verify/tests/data/cancel_verification.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "0",
"command": "cancel"
}
4 changes: 4 additions & 0 deletions verify/tests/data/cancel_verification_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "6",
"error_text": "The requestId 'cc121958d8fb4368aa3bb762bb9a0f75' does not exist or its no longer active."
}
8 changes: 8 additions & 0 deletions verify/tests/data/check_code.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"request_id": "c5037cb8b47449158ed6611afde58990",
"status": "0",
"event_id": "390f7296-aeff-45ba-8931-84a13f3f76d7",
"price": "0.05000000",
"currency": "EUR",
"estimated_price_messages_sent": "0.04675"
}
5 changes: 5 additions & 0 deletions verify/tests/data/check_code_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"request_id": "cc121958d8fb4368aa3bb762bb9a0f74",
"status": "16",
"error_text": "The code provided does not match the expected value"
}
32 changes: 32 additions & 0 deletions verify/tests/data/search_request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"request_id": "cc121958d8fb4368aa3bb762bb9a0f74",
"account_id": "abcdef01",
"status": "EXPIRED",
"number": "1234567890",
"price": "0",
"currency": "EUR",
"sender_id": "Acme Inc.",
"date_submitted": "2024-04-03 02:22:37",
"date_finalized": "2024-04-03 02:27:38",
"first_event_date": "2024-04-03 02:22:37",
"last_event_date": "2024-04-03 02:24:38",
"checks": [
{
"date_received": "2024-04-03 02:23:04",
"code": "1234",
"status": "INVALID",
"ip_address": ""
}
],
"events": [
{
"type": "sms",
"id": "23f3a13d-6d03-4262-8f4d-67f12a56e1c8"
},
{
"type": "sms",
"id": "09ef3984-3f62-453d-8f9c-1a161b373dba"
}
],
"estimated_price_messages_sent": "0.09350"
}
4 changes: 4 additions & 0 deletions verify/tests/data/search_request_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "101",
"error_text": "No response found"
}
64 changes: 64 additions & 0 deletions verify/tests/data/search_request_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"verification_requests": [
{
"request_id": "cc121958d8fb4368aa3bb762bb9a0f74",
"account_id": "abcdef01",
"number": "1234567890",
"sender_id": "verify",
"date_submitted": "2024-04-03 02:22:37",
"date_finalized": "2024-04-03 02:27:38",
"checks": [
{
"date_received": "2024-04-03 02:23:04",
"code": "1234",
"status": "INVALID",
"ip_address": ""
}
],
"first_event_date": "2024-04-03 02:22:37",
"last_event_date": "2024-04-03 02:24:38",
"price": "0",
"currency": "EUR",
"status": "EXPIRED",
"estimated_price_messages_sent": "0.09350",
"events": [
{
"id": "23f3a13d-6d03-4262-8f4d-67f12a56e1c8",
"type": "sms"
},
{
"id": "09ef3984-3f62-453d-8f9c-1a161b373dba",
"type": "sms"
}
]
},
{
"request_id": "c5037cb8b47449158ed6611afde58990",
"account_id": "abcdef01",
"number": "1234567890",
"sender_id": "verify",
"date_submitted": "2024-04-03 02:09:22",
"date_finalized": "2024-04-03 02:09:59",
"checks": [
{
"date_received": "2024-04-03 02:09:59",
"code": "5700",
"status": "VALID",
"ip_address": ""
}
],
"first_event_date": "2024-04-03 02:09:23",
"last_event_date": "2024-04-03 02:09:23",
"price": "0.05000000",
"currency": "EUR",
"status": "SUCCESS",
"estimated_price_messages_sent": "0.04675",
"events": [
{
"id": "390f7296-aeff-45ba-8931-84a13f3f76d7",
"type": "sms"
}
]
}
]
}
4 changes: 4 additions & 0 deletions verify/tests/data/trigger_next_event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "0",
"command": "trigger_next_event"
}
4 changes: 4 additions & 0 deletions verify/tests/data/trigger_next_event_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "19",
"error_text": "No more events are left to execute for the request ['2c021d25cf2e47a9b277a996f4325b81']"
}
Loading

0 comments on commit 8a22b14

Please sign in to comment.