diff --git a/voice/src/vonage_voice/models/__init__.py b/voice/src/vonage_voice/models/__init__.py index df81bace..a3661c98 100644 --- a/voice/src/vonage_voice/models/__init__.py +++ b/voice/src/vonage_voice/models/__init__.py @@ -42,11 +42,13 @@ Embedded, HalLinks, ) +from .webhooks import AnswerWebhook __all__ = [ "AdvancedMachineDetection", "AppEndpoint", "AudioStreamOptions", + "AnswerWebhook", "CallInfo", "CallList", "CallMessage", diff --git a/voice/src/vonage_voice/models/webhooks.py b/voice/src/vonage_voice/models/webhooks.py new file mode 100644 index 00000000..6fb84a1b --- /dev/null +++ b/voice/src/vonage_voice/models/webhooks.py @@ -0,0 +1,36 @@ +from typing import Optional + +from pydantic import BaseModel, ConfigDict, Field + + +class AnswerWebhook(BaseModel): + """Model for the Voice API Answer webhook payload. + + Args: + to (str, Optional): The number or endpoint that answered the call. + from_ (str, Optional): The number or endpoint that initiated the call. + from_user (str, Optional): The Client SDK user that initiated the call. + endpoint_type (str, Optional): The type of endpoint that answered the call. + uuid (str, Optional): The unique identifier for this call. + conversation_uuid (str, Optional): The unique identifier for this conversation. + region_url (str, Optional): Regional API endpoint to control the call. + custom_data (dict, Optional): Custom data object passed from the Client SDK. + sipheader_user_to_user (str, Optional): Content of the SIP User-to-User header, + received as the `SipHeader_User-to-User` parameter on the webhook. + """ + + model_config = ConfigDict(populate_by_name=True) + + to: Optional[str] = None + from_: Optional[str] = Field(None, alias='from') + from_user: Optional[str] = None + endpoint_type: Optional[str] = None + uuid: Optional[str] = None + conversation_uuid: Optional[str] = None + region_url: Optional[str] = None + custom_data: Optional[dict] = None + sipheader_user_to_user: Optional[str] = Field( + None, + validation_alias='SipHeader_User-to-User', + serialization_alias='SipHeader_User-to-User', + ) diff --git a/voice/tests/test_answer_webhook.py b/voice/tests/test_answer_webhook.py new file mode 100644 index 00000000..ab56057a --- /dev/null +++ b/voice/tests/test_answer_webhook.py @@ -0,0 +1,24 @@ +from vonage_voice.models import AnswerWebhook + + +def test_answer_webhook_sipheader_user_to_user_alias(): + payload = { + 'to': '442079460000', + 'from': '447700900000', + 'uuid': 'aaaaaaaa-bbbb-cccc-dddd-0123456789ab', + 'conversation_uuid': 'CON-aaaaaaaa-bbbb-cccc-dddd-0123456789ab', + 'SipHeader_User-to-User': '1234567890abcdef;encoding=hex', + } + + hook = AnswerWebhook(**payload) + + assert hook.to == '442079460000' + assert hook.from_ == '447700900000' + assert ( + hook.sipheader_user_to_user == '1234567890abcdef;encoding=hex' + ), 'Field should be populated from SipHeader_User-to-User' + + dumped = hook.model_dump(by_alias=True, exclude_none=True) + assert ( + dumped['SipHeader_User-to-User'] == '1234567890abcdef;encoding=hex' + ), 'Field should serialize back with the SipHeader_User-to-User key' diff --git a/voice/tests/test_voice.py b/voice/tests/test_voice.py index 87253fb3..9e002111 100644 --- a/voice/tests/test_voice.py +++ b/voice/tests/test_voice.py @@ -4,6 +4,7 @@ import responses from pytest import raises from responses.matchers import json_params_matcher +from testutils import build_response, get_mock_jwt_auth from vonage_http_client.http_client import HttpClient from vonage_voice import ( AudioStreamOptions, @@ -18,8 +19,6 @@ from vonage_voice.models.responses import CreateCallResponse from vonage_voice.voice import Voice -from testutils import build_response, get_mock_jwt_auth - path = abspath(__file__)