-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
resource(name='pyproject', source='pyproject.toml') | ||
file(name='readme', source='README.md') | ||
|
||
files(sources=['tests/data/*']) | ||
|
||
python_distribution( | ||
name='vonage-sms', | ||
dependencies=[ | ||
':pyproject', | ||
':readme', | ||
'sms/src/vonage_sms', | ||
], | ||
provides=python_artifact(), | ||
generate_setup=False, | ||
repositories=['@testpypi'], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Vonage SMS Package | ||
|
||
This package contains the code to use Vonage's SMS API with Python. | ||
|
||
## Usage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[project] | ||
name = 'vonage-sms' | ||
version = '0.1.0' | ||
description = 'Vonage SMS package' | ||
readme = "README.md" | ||
authors = [{ name = "Vonage", email = "devrel@vonage.com" }] | ||
requires-python = ">=3.8" | ||
dependencies = [ | ||
"vonage-http-client>=1.0.0", | ||
"vonage-utils>=1.0.0", | ||
"pydantic>=2.6.1", | ||
] | ||
classifiers = [ | ||
"Programming Language :: Python", | ||
"Programming Language :: Python :: 3", | ||
"Programming Language :: Python :: 3.8", | ||
"Programming Language :: Python :: 3.9", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
"Programming Language :: Python :: 3.12", | ||
"License :: OSI Approved :: Apache Software License", | ||
] | ||
|
||
[project.urls] | ||
homepage = "https://github.com/Vonage/vonage-python-sdk" | ||
|
||
[build-system] | ||
requires = ["setuptools>=61.0", "wheel"] | ||
build-backend = "setuptools.build_meta" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
python_sources() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from .sms import Sms | ||
|
||
__all__ = [ | ||
'Sms', | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from vonage_utils.errors import VonageError | ||
|
||
|
||
class SmsError(VonageError): | ||
"""Indicates an error with the Vonage SMS Package.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from copy import deepcopy | ||
from dataclasses import dataclass | ||
from typing import List, Literal, Optional, Union | ||
|
||
from pydantic import BaseModel, Field, field_validator, validate_call | ||
from vonage_http_client.http_client import HttpClient | ||
from vonage_sms.errors import SmsError | ||
|
||
|
||
class SmsMessage(BaseModel): | ||
to: str | ||
from_: str = Field(..., alias="from") | ||
text: str | ||
type: Optional[str] = None | ||
sig: Optional[str] = Field(None, min_length=16, max_length=60) | ||
status_report_req: Optional[int] = Field( | ||
None, | ||
alias="status-report-req", | ||
description="Set to 1 to receive a Delivery Receipt", | ||
) | ||
client_ref: Optional[str] = Field( | ||
None, alias="client-ref", description="Your own reference. Up to 40 characters." | ||
) | ||
network_code: Optional[str] = Field( | ||
None, | ||
alias="network-code", | ||
description="A 4-5 digit number that represents the mobile carrier network code", | ||
) | ||
|
||
|
||
@dataclass | ||
class SmsResponse: | ||
id: str | ||
|
||
|
||
class Sms: | ||
"""Calls Vonage's SMS API.""" | ||
|
||
def __init__(self, http_client: HttpClient) -> None: | ||
self._http_client = deepcopy(http_client) | ||
self._auth_type = 'basic' | ||
|
||
@validate_call | ||
def send(self, message: SmsMessage) -> SmsResponse: | ||
"""Send an SMS message.""" | ||
response = self._http_client.post( | ||
self._http_client.api_host, | ||
'/v2/ni', | ||
message.model_dump(), | ||
self._auth_type, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
python_tests(dependencies=['sms', 'testutils']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"request_id": "2c2f5d3f-93ac-42b1-9083-4b14f0d583d3", | ||
"type": "phone", | ||
"phone": { | ||
"phone": "1234567890", | ||
"carrier": "Verizon Wireless", | ||
"type": "MOBILE" | ||
}, | ||
"fraud_score": { | ||
"risk_score": "0", | ||
"risk_recommendation": "allow", | ||
"label": "low", | ||
"status": "completed" | ||
}, | ||
"sim_swap": { | ||
"status": "completed", | ||
"swapped": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"request_id": "2c2f5d3f-93ac-42b1-9083-4b14f0d583d3", | ||
"type": "phone", | ||
"phone": { | ||
"phone": "1234567890", | ||
"carrier": "Verizon Wireless", | ||
"type": "MOBILE" | ||
}, | ||
"fraud_score": { | ||
"risk_score": "0", | ||
"risk_recommendation": "allow", | ||
"label": "low", | ||
"status": "completed" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"request_id": "db5282b6-8046-4217-9c0e-d9c55d8696e9", | ||
"type": "phone", | ||
"phone": { | ||
"phone": "1234567890" | ||
}, | ||
"sim_swap": { | ||
"status": "completed", | ||
"swapped": false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
from dataclasses import asdict | ||
from os.path import abspath | ||
|
||
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_utils.errors import InvalidPhoneNumberError | ||
from vonage_utils.utils import remove_none_values | ||
|
||
from vonage_sms.sms import Sms | ||
from testutils import build_response | ||
|
||
path = abspath(__file__) | ||
|
||
sms = Sms(HttpClient(Auth('key', 'secret'))) | ||
|
||
|
||
def test_fraud_check_request_defaults(): | ||
request = FraudCheckRequest(phone='1234567890') | ||
assert request.type == 'phone' | ||
assert request.phone == '1234567890' | ||
assert request.insights == ['fraud_score', 'sim_swap'] | ||
|
||
|
||
def test_fraud_check_request_custom_insights(): | ||
request = FraudCheckRequest(phone='1234567890', insights=['fraud_score']) | ||
assert request.type == 'phone' | ||
assert request.phone == '1234567890' | ||
assert request.insights == ['fraud_score'] | ||
|
||
|
||
def test_fraud_check_request_invalid_phone(): | ||
with raises(InvalidPhoneNumberError): | ||
FraudCheckRequest(phone='invalid_phone') | ||
with raises(InvalidPhoneNumberError): | ||
FraudCheckRequest(phone='123') | ||
with raises(InvalidPhoneNumberError): | ||
FraudCheckRequest(phone='12345678901234567890') | ||
|
||
|
||
def test_fraud_check_request_invalid_insights(): | ||
with raises(ValidationError): | ||
FraudCheckRequest(phone='1234567890', insights=['invalid_insight']) | ||
|
||
|
||
@responses.activate | ||
def test_ni2_defaults(): | ||
build_response(path, 'POST', 'https://api.nexmo.com/v2/ni', 'default.json') | ||
request = FraudCheckRequest(phone='1234567890') | ||
response = ni2.fraud_check(request) | ||
assert type(response) == FraudCheckResponse | ||
assert response.request_id == '2c2f5d3f-93ac-42b1-9083-4b14f0d583d3' | ||
assert response.phone.carrier == 'Verizon Wireless' | ||
assert response.fraud_score.risk_score == '0' | ||
assert response.sim_swap.status == 'completed' | ||
|
||
|
||
@responses.activate | ||
def test_ni2_fraud_score_only(): | ||
build_response(path, 'POST', 'https://api.nexmo.com/v2/ni', 'fraud_score.json') | ||
request = FraudCheckRequest(phone='1234567890', insights=['fraud_score']) | ||
response = ni2.fraud_check(request) | ||
assert type(response) == FraudCheckResponse | ||
assert response.request_id == '2c2f5d3f-93ac-42b1-9083-4b14f0d583d3' | ||
assert response.phone.carrier == 'Verizon Wireless' | ||
assert response.fraud_score.risk_score == '0' | ||
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 | ||
|
||
|
||
@responses.activate | ||
def test_ni2_sim_swap_only(): | ||
build_response(path, 'POST', 'https://api.nexmo.com/v2/ni', 'sim_swap.json') | ||
request = FraudCheckRequest(phone='1234567890', insights='sim_swap') | ||
response = ni2.fraud_check(request) | ||
assert type(response) == FraudCheckResponse | ||
assert response.request_id == 'db5282b6-8046-4217-9c0e-d9c55d8696e9' | ||
assert response.phone.phone == '1234567890' | ||
assert response.fraud_score is None | ||
assert response.sim_swap.status == 'completed' | ||
assert response.sim_swap.swapped is False | ||
|
||
clear_response = asdict(response, dict_factory=remove_none_values) | ||
assert 'fraud_score' not in clear_response | ||
assert 'sim_swap' in clear_response | ||
assert 'reason' not in clear_response['sim_swap'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters