Skip to content

Commit

Permalink
finish Users API implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkahan committed Mar 28, 2024
1 parent 4c9b303 commit ff65eac
Show file tree
Hide file tree
Showing 24 changed files with 223 additions and 91 deletions.
10 changes: 7 additions & 3 deletions http_client/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# 1.0.0
- Initial upload
# 1.1.1
- Add new Patch method
- New input fields for different ways to pass data in a request

# 1.1.0
- Add support for signature authentication
- Add support for signature authentication

# 1.0.0
- Initial upload
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.1.0"
version = "1.1.1"
description = "An HTTP client for making requests to Vonage APIs."
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
Expand Down
2 changes: 1 addition & 1 deletion http_client/src/vonage_http_client/errors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from json import dumps, JSONDecodeError
from json import JSONDecodeError, dumps

from requests import Response
from vonage_utils.errors import VonageError
Expand Down
30 changes: 18 additions & 12 deletions http_client/src/vonage_http_client/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Literal, Optional, Union

from pydantic import BaseModel, Field, ValidationError, validate_call
from requests import Response, delete
from requests import Response
from requests.adapters import HTTPAdapter
from requests.sessions import Session
from typing_extensions import Annotated
Expand Down Expand Up @@ -107,30 +107,34 @@ def post(
request_path: str = '',
params: dict = None,
auth_type: Literal['jwt', 'basic', 'signature'] = 'jwt',
body_type: Literal['json', 'data'] = 'json',
sent_data_type: Literal['json', 'data'] = 'json',
) -> Union[dict, None]:
return self.make_request('POST', host, request_path, params, auth_type, body_type)
return self.make_request(
'POST', host, request_path, params, auth_type, sent_data_type
)

def get(
self,
host: str,
request_path: str = '',
params: dict = None,
auth_type: Literal['jwt', 'basic', 'signature'] = 'jwt',
body_type: Literal['json', 'data'] = 'json',
sent_data_type: Literal['json', 'form', 'query_params'] = 'json',
) -> Union[dict, None]:
return self.make_request('GET', host, request_path, params, auth_type, body_type)
return self.make_request(
'GET', host, request_path, params, auth_type, sent_data_type
)

def patch(
self,
host: str,
request_path: str = '',
params: dict = None,
auth_type: Literal['jwt', 'basic', 'signature'] = 'jwt',
body_type: Literal['json', 'data'] = 'json',
sent_data_type: Literal['json', 'form', 'query_params'] = 'json',
) -> Union[dict, None]:
return self.make_request(
'PATCH', host, request_path, params, auth_type, body_type
'PATCH', host, request_path, params, auth_type, sent_data_type
)

def delete(
Expand All @@ -139,10 +143,10 @@ def delete(
request_path: str = '',
params: dict = None,
auth_type: Literal['jwt', 'basic', 'signature'] = 'jwt',
body_type: Literal['json', 'data'] = 'json',
sent_data_type: Literal['json', 'form', 'query_params'] = 'json',
) -> Union[dict, None]:
return self.make_request(
'DELETE', host, request_path, params, auth_type, body_type
'DELETE', host, request_path, params, auth_type, sent_data_type
)

@validate_call
Expand All @@ -153,7 +157,7 @@ def make_request(
request_path: str = '',
params: Optional[dict] = None,
auth_type: Literal['jwt', 'basic', 'signature'] = 'jwt',
body_type: Literal['json', 'data'] = 'json',
sent_data_type: Literal['json', 'form', 'query_params'] = 'json',
):
url = f'https://{host}{request_path}'
logger.debug(
Expand All @@ -174,10 +178,12 @@ def make_request(
'timeout': self._timeout,
}

if body_type == 'json':
if sent_data_type == 'json':
self._headers['Content-Type'] = 'application/json'
request_params['json'] = params
else:
elif sent_data_type == 'query_params':
request_params['params'] = params
elif sent_data_type == 'form':
request_params['data'] = params

with self._session.request(**request_params) as response:
Expand Down
13 changes: 10 additions & 3 deletions http_client/tests/test_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,19 @@ def test_create_http_client_invalid_options_error():

@responses.activate
def test_make_get_request():
build_response(path, 'GET', 'https://example.com/get_json', 'example_get.json')
build_response(
path, 'GET', 'https://example.com/get_json?key=value', 'example_get.json'
)
client = HttpClient(
Auth(application_id=application_id, private_key=private_key),
http_client_options={'api_host': 'example.com'},
)
res = client.get(host='example.com', request_path='/get_json')
res = client.get(
host='example.com',
request_path='/get_json',
params={'key': 'value'},
sent_data_type='query_params',
)

assert res['hello'] == 'world'
assert responses.calls[0].request.headers['User-Agent'] == client._user_agent
Expand Down Expand Up @@ -131,7 +138,7 @@ def test_make_post_request_with_signature():
request_path='/post_signed_params',
params=params,
auth_type='signature',
body_type='data',
sent_data_type='form',
)
assert res['hello'] == 'world!'

Expand Down
5 changes: 2 additions & 3 deletions number_insight_v2/tests/test_number_insight_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import responses
from pydantic import ValidationError
from pytest import raises
from vonage_http_client.auth import Auth
from vonage_http_client.http_client import HttpClient
from vonage_number_insight_v2.number_insight_v2 import (
FraudCheckRequest,
Expand All @@ -14,11 +13,11 @@
from vonage_utils.errors import InvalidPhoneNumberError
from vonage_utils.utils import remove_none_values

from testutils import build_response
from testutils import build_response, get_mock_api_key_auth

path = abspath(__file__)

ni2 = NumberInsightV2(HttpClient(Auth('key', 'secret')))
ni2 = NumberInsightV2(HttpClient(get_mock_api_key_auth()))


def test_fraud_check_request_defaults():
Expand Down
6 changes: 6 additions & 0 deletions sms/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# 1.0.2
- Internal refactoring

# 1.0.1
- Internal refactoring

# 1.0.0
- Initial upload
4 changes: 2 additions & 2 deletions sms/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[project]
name = 'vonage-sms'
version = '1.0.1'
version = '1.0.2'
description = 'Vonage SMS package'
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-http-client>=1.1.0",
"vonage-http-client>=1.1.1",
"vonage-utils>=1.0.0",
"pydantic>=2.6.1",
]
Expand Down
7 changes: 4 additions & 3 deletions sms/src/vonage_sms/sms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Sms:

def __init__(self, http_client: HttpClient) -> None:
self._http_client = http_client
self._body_type = 'data'
self._sent_data_type = 'form'
if self._http_client._auth._signature_secret:
self._auth_type = 'signature'
else:
Expand All @@ -27,7 +27,7 @@ def send(self, message: SmsMessage) -> SmsResponse:
'/sms/json',
message.model_dump(by_alias=True),
self._auth_type,
self._body_type,
self._sent_data_type,
)

if int(response['message-count']) > 1:
Expand Down Expand Up @@ -78,9 +78,10 @@ def submit_sms_conversion(
'%Y-%m-%d %H:%M:%S'
),
}
self._http_client.get(
self._http_client.post(
self._http_client.api_host,
'/conversions/sms',
params,
self._auth_type,
self._sent_data_type,
)
4 changes: 2 additions & 2 deletions sms/tests/test_sms.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def test_send_message_error():
def test_submit_sms_conversion():
build_response(
path,
'GET',
'POST',
'https://api.nexmo.com/conversions/sms',
'null',
)
Expand All @@ -162,7 +162,7 @@ def test_submit_sms_conversion():
def test_submit_sms_conversion_402():
build_response(
path,
'GET',
'POST',
'https://api.nexmo.com/conversions/sms',
'conversion_not_enabled.html',
status_code=402,
Expand Down
54 changes: 44 additions & 10 deletions users/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,56 @@ It is recommended to use this as part of the main `vonage` package. The examples

### List Users

### Create a New User
With no custom options specified, this method will get the last 100 users. It returns a tuple consisting of a list of `UserSummary` objects and a string describing the cursor to the next page of results.

### Get a User
```python
from vonage_users import ListUsersRequest

### Update a User
users, _ = vonage_client.users.list_users()

### Delete a User
# With options
params = ListUsersRequest(
page_size=10,
cursor=my_cursor,
order='desc',
)
users, next_cursor = vonage_client.users.list_users(params)
```

### Create a New User

<!-- ### Manage a User
```python
from vonage_users import User, Channels, SmsChannel
user_options = User(
name='my_user_name',
display_name='My User Name',
properties={'custom_key': 'custom_value'},
channels=Channels(sms=[SmsChannel(number='1234567890')]),
)
user = vonage_client.users.create_user(user_options)
```

Create a `User` object, then pass into the `Users.create` or `Users.update` method.
### Get a User

```python
from vonage_users import User, UserResponse
user = client.users.get_user('USR-87e3e6b0-cd7b-45ef-a0a7-bcd5566a672b')
user_as_dict = user.model_dump(exclude_none=True)
```

user = User(name='John Doe', email='john.doe@example.com')
response: UserResponse = vonage_client.users.create(user)
### Update a User
```python
from vonage_users import User, Channels, SmsChannel, WhatsappChannel
user_options = User(
name='my_user_name',
display_name='My User Name',
properties={'custom_key': 'custom_value'},
channels=Channels(sms=[SmsChannel(number='1234567890')], whatsapp=[WhatsappChannel(number='9876543210')]),
)
user = vonage_client.users.update_user(id, user_options)
```

print(response.model_dump(exclude_unset=True)) -->
### Delete a User

```python
vonage_client.users.delete_user(id)
```
2 changes: 1 addition & 1 deletion users/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.1.0",
"vonage-http-client>=1.1.1",
"vonage-utils>=1.0.0",
"pydantic>=2.6.1",
]
Expand Down
9 changes: 6 additions & 3 deletions users/src/vonage_users/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# from .errors import PartialFailureError, SmsError
# from .requests import SmsMessage
# from .responses import MessageResponse, SmsResponse
from .common import User
from .requests import ListUsersRequest
from .responses import UserSummary
from .users import Users

__all__ = [
'Users',
'User',
'ListUsersRequest',
'UserSummary',
]
11 changes: 1 addition & 10 deletions users/src/vonage_users/common.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
from dataclasses import field
from typing import List, Optional

from pydantic import (
BaseModel,
Field,
ValidationInfo,
field_validator,
model_validator,
root_validator,
)
from pydantic import BaseModel, Field, model_validator
from typing_extensions import Annotated


PhoneNumber = Annotated[str, Field(pattern=r'^[1-9]\d{6,14}$')]


Expand Down
5 changes: 0 additions & 5 deletions users/src/vonage_users/errors.py

This file was deleted.

1 change: 0 additions & 1 deletion users/src/vonage_users/responses.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import List, Optional

from pydantic import BaseModel, Field, model_validator

from vonage_users.common import Link, ResourceLink


Expand Down
Loading

0 comments on commit ff65eac

Please sign in to comment.