Skip to content

Commit

Permalink
finish verify v2 and prepare for release
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkahan committed Apr 8, 2024
1 parent 2e3ff3b commit 10ae9b9
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 84 deletions.
3 changes: 3 additions & 0 deletions http_client/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 1.2.1
- Expose classes and errors at the package level

# 1.2.0
- Add `last_request` and `last_response` properties
- Add new `Forbidden` error
Expand Down
13 changes: 13 additions & 0 deletions http_client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,17 @@ The `HttpClient` class automatically handles JWT and basic authentication based
```python
# Use basic authentication for this request
response = client.get(host='api.nexmo.com', request_path='/v1/messages', auth_type='basic')
```

### Catching errors

Error objects are exposed in the package scope, so you can catch errors like this:

```python
from vonage_http_client import HttpRequestError

try:
client.post(...)
except HttpRequestError:
...
```
2 changes: 1 addition & 1 deletion http_client/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "vonage-http-client"
version = "1.2.0"
version = "1.2.1"
description = "An HTTP client for making requests to Vonage APIs."
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
Expand Down
28 changes: 28 additions & 0 deletions http_client/src/vonage_http_client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from .auth import Auth
from .errors import (
AuthenticationError,
ForbiddenError,
HttpRequestError,
InvalidAuthError,
InvalidHttpClientOptionsError,
JWTGenerationError,
NotFoundError,
RateLimitedError,
ServerError,
)
from .http_client import HttpClient, HttpClientOptions

__all__ = [
'Auth',
'AuthenticationError',
'ForbiddenError',
'HttpRequestError',
'InvalidAuthError',
'InvalidHttpClientOptionsError',
'JWTGenerationError',
'NotFoundError',
'RateLimitedError',
'ServerError',
'HttpClient',
'HttpClientOptions',
]
3 changes: 3 additions & 0 deletions verify/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# 1.0.1
- Internal refactoring

# 1.0.0
- Initial upload
4 changes: 2 additions & 2 deletions verify/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[project]
name = 'vonage-verify'
version = '1.0.0'
version = '1.0.1'
description = 'Vonage verify package'
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-http-client>=1.2.0",
"vonage-http-client>=1.2.1",
"vonage-utils>=1.0.1",
"pydantic>=2.6.1",
]
Expand Down
58 changes: 24 additions & 34 deletions verify_v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,49 @@ This package contains the code to use [Vonage's Verify v2 API](https://developer

It is recommended to use this as part of the main `vonage` package. The examples below assume you've created an instance of the `vonage.Vonage` class called `vonage_client`.


######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

### Make a Verify Request

```python
from vonage_verify import VerifyRequest
params = {'number': '1234567890', 'brand': 'Acme Inc.'}
request = VerifyRequest(**params)
response = vonage_client.verify.start_verification(request)
from vonage_verify_v2 import VerifyRequest, SmsChannel
# All channels have associated models
sms_channel = SmsChannel(to='1234567890')
params = {
'brand': 'Vonage',
'workflow': [sms_channel],
}
verify_request = VerifyRequest(**params)

response = vonage_client.verify_v2.start_verification(verify_request)
```

### Make a PSD2 (Payment Services Directive v2) Request
If using silent authentication, the response will include a `check_url` field with a url that should be accessed on the user's device to proceed with silent authentication. If used, silent auth must be the first element in the `workflow` list.

```python
from vonage_verify import Psd2Request
params = {'number': '1234567890', 'payee': 'Acme Inc.', 'amount': 99.99}
request = VerifyRequest(**params)
response = vonage_client.verify.start_verification(request)
silent_auth_channel = SilentAuthChannel(channel=ChannelType.SILENT_AUTH, to='1234567890')
sms_channel = SmsChannel(to='1234567890')
params = {
'brand': 'Vonage',
'workflow': [silent_auth_channel, sms_channel],
}
verify_request = VerifyRequest(**params)

response = vonage_client.verify_v2.start_verification(verify_request)
```

### Check a Verification Code

```python
vonage_client.verify.check_code(request_id='my_request_id', code='1234')
```

### Search Verification Requests

```python
# Search for single request
response = vonage_client.verify.search('my_request_id')

# Search for multiple requests
response = vonage_client.verify.search(['my_request_id_1', 'my_request_id_2'])
vonage_client.verify_v2.check_code(request_id='my_request_id', code='1234')
```

### Cancel a Verification

```python
response = vonage_client.verify.cancel_verification('my_request_id')
vonage_client.verify_v2.cancel_verification('my_request_id')
```

### Trigger the Next Workflow Event

```python
response = vonage_client.verify.trigger_next_event('my_request_id')
```

### Request a Network Unblock

Note: Network Unblock is switched off by default. Contact Sales to enable the Network Unblock API for your account.

```python
response = vonage_client.verify.request_network_unblock('23410')
```
vonage_client.verify_v2.trigger_next_workflow('my_request_id')
```
2 changes: 1 addition & 1 deletion verify_v2/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-http-client>=1.2.0",
"vonage-http-client>=1.2.1",
"vonage-utils>=1.0.1",
"pydantic>=2.6.1",
]
Expand Down
3 changes: 2 additions & 1 deletion verify_v2/src/vonage_verify_v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
VoiceChannel,
WhatsappChannel,
)
from .responses import StartVerificationResponse
from .responses import CheckCodeResponse, StartVerificationResponse
from .verify_v2 import VerifyV2

__all__ = [
'VerifyV2',
'VerifyError',
'ChannelType',
'CheckCodeResponse',
'Locale',
'VerifyRequest',
'SilentAuthChannel',
Expand Down
16 changes: 4 additions & 12 deletions verify_v2/src/vonage_verify_v2/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ def check_valid_from_field(cls, v):
if (
v is not None
and type(v) is not PhoneNumber
and not search(r'^[a-zA-Z0-9]{1,15}$', v)
and not search(r'^[a-zA-Z0-9]{3,11}$', v)
):
raise VerifyError(
'You must specify a valid "from_" value if included. '
'It must be a valid phone number without the leading +, or a string of 1-15 alphanumeric characters. '
'It must be a valid phone number without the leading +, or a string of 3-11 alphanumeric characters. '
f'You set "from_": "{v}".'
)
return v
Expand All @@ -48,10 +48,10 @@ class WhatsappChannel(Channel):
@field_validator('from_')
@classmethod
def check_valid_sender(cls, v):
if type(v) is not PhoneNumber and not search(r'^[a-zA-Z0-9]{1,15}$', v):
if type(v) is not PhoneNumber and not search(r'^[a-zA-Z0-9]{3,11}$', v):
raise VerifyError(
f'You must specify a valid "from_" value. '
'It must be a valid phone number without the leading +, or a string of 1-15 alphanumeric characters. '
'It must be a valid phone number without the leading +, or a string of 3-11 alphanumeric characters. '
f'You set "from_": "{v}".'
)
return v
Expand Down Expand Up @@ -84,14 +84,6 @@ class VerifyRequest(BaseModel):
code_length: Optional[int] = Field(None, ge=4, le=10)
code: Optional[str] = Field(None, pattern=r'^[a-zA-Z0-9]{4,10}$')

@model_validator(mode='after')
def remove_fields_if_only_silent_auth(self):
if len(self.workflow) == 1 and isinstance(self.workflow[0], SilentAuthChannel):
self.locale = None
self.code_length = None
self.code = None
return self

@model_validator(mode='after')
def check_silent_auth_first_if_present(self):
if len(self.workflow) > 1:
Expand Down
8 changes: 5 additions & 3 deletions verify_v2/src/vonage_verify_v2/verify_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ def cancel_verification(self, request_id: str) -> None:

@validate_call
def trigger_next_workflow(self, request_id: str) -> None:
"""Trigger the next workflow event in the verification process.
"""Trigger the next workflow event in the list of workflows passed in when making the
request.
Args:
request_id (str): The request ID.
"""
response = self._http_client.post(
self._http_client.api_host, f'/v2/verify/{request_id}'
self._http_client.post(
self._http_client.api_host,
f'/v2/verify/{request_id}/next_workflow',
)
6 changes: 6 additions & 0 deletions verify_v2/tests/data/trigger_next_workflow_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"title": "Conflict",
"detail": "There are no more events left to trigger.",
"instance": "4d731cb7-25d3-487a-9ea0-f6b5811b534f",
"type": "https://developer.nexmo.com/api-errors#conflict"
}
7 changes: 0 additions & 7 deletions verify_v2/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,6 @@ def test_create_verify_request():
assert verify_request.code_length == 6
assert verify_request.code == '123456'

# Silent auth only
params['workflow'] = [silent_auth_channel]
verify_request = VerifyRequest(**params)
assert verify_request.locale == None
assert verify_request.code_length == None
assert verify_request.code == None


def test_create_verify_request_error():
params = {
Expand Down
38 changes: 24 additions & 14 deletions verify_v2/tests/test_verify_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def test_make_verify_request_full():


@responses.activate
def test_verify_request_error():
def test_verify_request_concurrent_verifications_error():
build_response(
path,
'POST',
Expand Down Expand Up @@ -155,20 +155,30 @@ def test_cancel_verification():

@responses.activate
def test_trigger_next_workflow():
response = verify.trigger_next_event('c5037cb8b47449158ed6611afde58990')
responses.add(
responses.POST,
'https://api.nexmo.com/v2/verify/36e7060d-2b23-4257-bad0-773ab47f85ef/next_workflow',
status=200,
)
assert verify.trigger_next_workflow('36e7060d-2b23-4257-bad0-773ab47f85ef') is None
assert verify._http_client.last_response.status_code == 200


# @responses.activate
# def test_trigger_next_event_error():
# build_response(
# path,
# 'POST',
# 'https://api.nexmo.com/verify/control/json',
# 'trigger_next_event_error.json',
# )
@responses.activate
def test_trigger_next_event_error():
build_response(
path,
'POST',
'https://api.nexmo.com/v2/verify/36e7060d-2b23-4257-bad0-773ab47f85ef/next_workflow',
'trigger_next_workflow_error.json',
status_code=409,
)

# with raises(VerifyError) as e:
# verify.trigger_next_event('2c021d25cf2e47a9b277a996f4325b81')
with raises(HttpRequestError) as e:
verify.trigger_next_workflow('36e7060d-2b23-4257-bad0-773ab47f85ef')

# assert e.match("'status': '19")
# assert e.match('No more events are left to execute for the request')
assert e.value.response.status_code == 409
assert e.value.response.json()['title'] == 'Conflict'
assert (
e.value.response.json()['detail'] == 'There are no more events left to trigger.'
)
4 changes: 4 additions & 0 deletions vonage/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.99.0a5
- Add support for the [Vonage Verify V2 API](https://developer.vonage.com/en/verify/overview).
- Expose error classes at the top level of the `vonage-http-client` package.

# 3.99.0a4
- Add support for the [Vonage Verify API](https://developer.vonage.com/en/api/verify).
- Add `last_request` and `last_response` properties to the HTTP Client.
Expand Down
5 changes: 3 additions & 2 deletions vonage/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-utils>=1.0.1",
"vonage-http-client>=1.2.0",
"vonage-http-client>=1.2.1",
"vonage-number-insight-v2>=0.1.0",
"vonage-sms>=1.0.2",
"vonage-users>=1.0.1",
"vonage-verify>=1.0.0",
"vonage-verify>=1.0.1",
"vonage-verify-v2>=1.0.0",
]
classifiers = [
"Programming Language :: Python",
Expand Down
2 changes: 1 addition & 1 deletion vonage/src/vonage/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.99.0a4'
__version__ = '3.99.0a5'
11 changes: 5 additions & 6 deletions vonage/src/vonage/vonage.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from typing import Optional

from vonage_http_client.auth import Auth
from vonage_http_client.http_client import HttpClient, HttpClientOptions
from vonage_number_insight_v2.number_insight_v2 import NumberInsightV2
from vonage_sms.sms import Sms
from vonage_users.users import Users
from vonage_verify.verify import Verify
from vonage_http_client import Auth, HttpClient, HttpClientOptions
from vonage_number_insight_v2 import NumberInsightV2
from vonage_sms import Sms
from vonage_users import Users
from vonage_verify import Verify
from vonage_verify_v2 import VerifyV2

from ._version import __version__
Expand Down

0 comments on commit 10ae9b9

Please sign in to comment.