Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions messages/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 1.5.0
- Add an optional "failover" property to `vonage_messages.Messages.send`

# 1.4.0
- Make all models originally accessed by `vonage_messages.models.***` available at the top level of the package, i.e. `vonage_messages.***`

Expand Down
2 changes: 1 addition & 1 deletion messages/src/vonage_messages/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.4.0'
__version__ = '1.5.0'
18 changes: 16 additions & 2 deletions messages/src/vonage_messages/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,35 @@ def http_client(self) -> HttpClient:
return self._http_client

@validate_call
def send(self, message: BaseMessage) -> SendMessageResponse:
def send(
self, message: BaseMessage, failover: list[BaseMessage] = None
) -> SendMessageResponse:
"""Send a message using Vonage's Messages API.

Args:
message (BaseMessage): The message to be sent as a Pydantic model.
Use the provided models (in `vonage_messages.models`) to create messages and pass them in to this method.
failover (list[BaseMessage]): A list of failover messages to be attempted if the primary message fails.

Returns:
SendMessageResponse: Response model containing the unique identifier of the sent message.
Access the identifier with the `message_uuid` attribute.
"""
body = message.model_dump(by_alias=True, exclude_none=True) or message

if failover is not None:
failover_body = [
m.model_dump(by_alias=True, exclude_none=True) or m for m in failover
]
body = {
**body,
'failover': failover_body,
}

response = self._http_client.post(
self._http_client.api_host,
'/v1/messages',
message.model_dump(by_alias=True, exclude_none=True) or message,
body,
self._auth_type,
)

Expand Down
2 changes: 1 addition & 1 deletion messages/src/vonage_messages/models/rcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class BaseRcs(BaseMessage):
"""

to: PhoneNumber
from_: str = Field(..., serialization_alias='from', pattern='^[a-zA-Z0-9]+$')
from_: str = Field(..., serialization_alias='from', pattern='^[a-zA-Z0-9-_]+$')
ttl: Optional[int] = Field(None, ge=300, le=259200)
channel: ChannelType = ChannelType.RCS

Expand Down
4 changes: 4 additions & 0 deletions messages/src/vonage_messages/responses.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from pydantic import BaseModel


Expand All @@ -6,6 +8,8 @@ class SendMessageResponse(BaseModel):

Attributes:
message_uuid (str): The UUID of the sent message.
workflow_id [str]: Workflow ID if the `failover` parameter was used in the request.
"""

message_uuid: str
workflow_id: Optional[str] = None
4 changes: 4 additions & 0 deletions messages/tests/data/send_message_with_failover.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"message_uuid": "d8f86df1-dec6-442f-870a-2241be27d721",
"workflow_id": "3TcNjguHxr2vcCZ9Ddsnq6tw8yQUpZ9rMHv9QXSxLan5ibMxqSzLdx9"
}
44 changes: 44 additions & 0 deletions messages/tests/test_messages.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from json import loads
from os.path import abspath

import responses
Expand Down Expand Up @@ -51,6 +52,49 @@ def test_send_message():
assert messages._auth_type == 'jwt'


@responses.activate
def test_send_message_with_failover():
build_response(
path,
'POST',
'https://api.nexmo.com/v1/messages',
'send_message_with_failover.json',
202,
)
sms = Sms(
from_='Vonage APIs',
to='1234567890',
text='Hello, World!',
)
failover = [
Sms(from_='Vonage APIs', to='1987654321', text='Failover message'),
]

response = messages.send(sms, failover=failover)
print(messages._http_client.last_request.body)
assert loads(messages._http_client.last_request.body) == {
"to": "1234567890",
"from": "Vonage APIs",
"text": "Hello, World!",
"channel": "sms",
"message_type": "text",
"failover": [
{
"to": "1987654321",
"from": "Vonage APIs",
"text": "Failover message",
"channel": "sms",
"message_type": "text",
}
],
}
assert response.message_uuid == 'd8f86df1-dec6-442f-870a-2241be27d721'
assert (
response.workflow_id == '3TcNjguHxr2vcCZ9Ddsnq6tw8yQUpZ9rMHv9QXSxLan5ibMxqSzLdx9'
)
assert messages._auth_type == 'jwt'


@responses.activate
def test_send_message_basic_auth():
build_response(
Expand Down
3 changes: 3 additions & 0 deletions vonage/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 4.5.0
- vonage-messages: add an optional "failover" property to `vonage_messages.Messages.send`

# 4.4.3
- vonage-number-insight: use basic header auth instead of request body auth

Expand Down
6 changes: 3 additions & 3 deletions vonage/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ description = "Python Server SDK for using Vonage APIs"
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"vonage-utils>=1.1.4",
"vonage-http-client>=1.5.1",
"vonage-account>=1.1.1",
"vonage-application>=2.0.1",
"vonage-messages>=1.4.0",
"vonage-http-client>=1.5.1",
"vonage-messages>=1.5.0",
"vonage-network-auth>=1.0.2",
"vonage-network-sim-swap>=1.1.2",
"vonage-network-number-verification>=1.0.2",
Expand All @@ -18,6 +17,7 @@ dependencies = [
"vonage-sms>=1.1.6",
"vonage-subaccounts>=1.0.4",
"vonage-users>=1.2.1",
"vonage-utils>=1.1.4",
"vonage-verify>=2.1.0",
"vonage-verify-legacy>=1.0.1",
"vonage-video>=1.2.0",
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__ = '4.4.3'
__version__ = '4.5.0'