diff --git a/messages/CHANGES.md b/messages/CHANGES.md index 7183d872..45cf1396 100644 --- a/messages/CHANGES.md +++ b/messages/CHANGES.md @@ -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.***` diff --git a/messages/src/vonage_messages/_version.py b/messages/src/vonage_messages/_version.py index 96e3ce8d..77f1c8e6 100644 --- a/messages/src/vonage_messages/_version.py +++ b/messages/src/vonage_messages/_version.py @@ -1 +1 @@ -__version__ = '1.4.0' +__version__ = '1.5.0' diff --git a/messages/src/vonage_messages/messages.py b/messages/src/vonage_messages/messages.py index 3fd62f65..6ba05b98 100644 --- a/messages/src/vonage_messages/messages.py +++ b/messages/src/vonage_messages/messages.py @@ -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, ) diff --git a/messages/src/vonage_messages/models/rcs.py b/messages/src/vonage_messages/models/rcs.py index ef856061..b0e98a1a 100644 --- a/messages/src/vonage_messages/models/rcs.py +++ b/messages/src/vonage_messages/models/rcs.py @@ -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 diff --git a/messages/src/vonage_messages/responses.py b/messages/src/vonage_messages/responses.py index 59a84b50..99e594ed 100644 --- a/messages/src/vonage_messages/responses.py +++ b/messages/src/vonage_messages/responses.py @@ -1,3 +1,5 @@ +from typing import Optional + from pydantic import BaseModel @@ -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 diff --git a/messages/tests/data/send_message_with_failover.json b/messages/tests/data/send_message_with_failover.json new file mode 100644 index 00000000..7a8a12be --- /dev/null +++ b/messages/tests/data/send_message_with_failover.json @@ -0,0 +1,4 @@ +{ + "message_uuid": "d8f86df1-dec6-442f-870a-2241be27d721", + "workflow_id": "3TcNjguHxr2vcCZ9Ddsnq6tw8yQUpZ9rMHv9QXSxLan5ibMxqSzLdx9" +} \ No newline at end of file diff --git a/messages/tests/test_messages.py b/messages/tests/test_messages.py index 51c8767b..5cde1bc0 100644 --- a/messages/tests/test_messages.py +++ b/messages/tests/test_messages.py @@ -1,3 +1,4 @@ +from json import loads from os.path import abspath import responses @@ -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( diff --git a/vonage/CHANGES.md b/vonage/CHANGES.md index 185e6aa3..f75f9a3b 100644 --- a/vonage/CHANGES.md +++ b/vonage/CHANGES.md @@ -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 diff --git a/vonage/pyproject.toml b/vonage/pyproject.toml index c04e105f..3ac25bb2 100644 --- a/vonage/pyproject.toml +++ b/vonage/pyproject.toml @@ -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", @@ -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", diff --git a/vonage/src/vonage/_version.py b/vonage/src/vonage/_version.py index 77ed0d0b..330025d8 100644 --- a/vonage/src/vonage/_version.py +++ b/vonage/src/vonage/_version.py @@ -1 +1 @@ -__version__ = '4.4.3' +__version__ = '4.5.0'