diff --git a/sdk/communication/azure-communication-sms/CHANGELOG.md b/sdk/communication/azure-communication-sms/CHANGELOG.md index 0af08f9be347..01806b00a435 100644 --- a/sdk/communication/azure-communication-sms/CHANGELOG.md +++ b/sdk/communication/azure-communication-sms/CHANGELOG.md @@ -1,5 +1,16 @@ # Release History +## 1.0.0b6 (Unreleased) +### Added +- Added support for 1:N SMS messaging. +- Added support for SMS idempotency. +- Send method series in SmsClient are idempotent under retry policy. +- Added support for tagging SMS messages. + +### Breaking +- Send method takes in strings for phone numbers instead of `PhoneNumberIdentifier`. +- Send method returns a list of `SmsSendResult`s instead of a `SendSmsResponse`. + ## 1.0.0b5 (2021-02-09) ### Added - Added support for Azure Active Directory authentication. diff --git a/sdk/communication/azure-communication-sms/README.md b/sdk/communication/azure-communication-sms/README.md index 7e72a8b6d0fc..5ed08aa784e7 100644 --- a/sdk/communication/azure-communication-sms/README.md +++ b/sdk/communication/azure-communication-sms/README.md @@ -28,14 +28,14 @@ pip install azure-communication-sms ## Key concepts Azure Communication SMS package is used to do following: -- Send an SMS +- Send SMS Messages ## Examples The following section provides several code snippets covering some of the most common Azure Communication Services tasks, including: - [Client Initialization](#client-initialization) -- [Sending an SMS](#sending-an-sms) +- [Sending SMS Messages](#sending--zsms) ### Client Initialization @@ -54,23 +54,27 @@ endpoint = os.getenv('AZURE_COMMUNICATION_SERVICE_ENDPOINT') sms_client = SmsClient(endpoint, DefaultAzureCredential()) ``` -### Sending an SMS +### Sending SMS Messages Once the client is initialized, the `.send()` method can be invoked: ```Python -from azure.communication.sms import SendSmsOptions, PhoneNumberIdentifier +from azure.communication.sms import SendSmsOptions -smsresponse = sms_client.send( +sms_responses = sms_client.send( from_phone_number=PhoneNumberIdentifier(""), - to_phone_number=[PhoneNumberIdentifier("")], + to_phone_numbers=["", "", ""], message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property ``` -- `from-phone-number`: an SMS enabled phone number associated with your communication service -- `to-phone-number`: the phone number you wish to send a message to -- `send_sms_options`: an optional parameter that you can use to configure Delivery Reporting. This is useful for scenarios where you want to emit events when SMS messages are delivered. +- `from_phone_number`: An SMS enabled phone number associated with your communication service. +- `to_phone_numbers`: The phone numbers you wish to send a message to. +- `message`: The message that you want to send. +- `enable_delivery_report`: An optional parameter that you can use to configure delivery reporting. This is useful for scenarios where you want to emit events when SMS messages are delivered. +- `tag`: An optional parameter that you can use to configure custom tagging. + ## Troubleshooting The Azure Communication Service Identity client will raise exceptions defined in [Azure Core](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/README.md). @@ -93,4 +97,7 @@ When you submit a pull request, a CLA-bot will automatically determine whether y PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. \ No newline at end of file +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + + +[azure_core]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/README.md \ No newline at end of file diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/__init__.py b/sdk/communication/azure-communication-sms/azure/communication/sms/__init__.py index c44b589aa2ac..f1e383aa3376 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/__init__.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/__init__.py @@ -1,17 +1,8 @@ from ._sms_client import SmsClient -from ._shared.models import ( - PhoneNumberIdentifier, -) - -from ._generated.models import ( - SendSmsOptions, - SendSmsResponse, -) +from ._models import SmsSendResult __all__ = [ 'SmsClient', - 'PhoneNumberIdentifier', - 'SendSmsOptions', - 'SendSmsResponse', + 'SmsSendResult', ] diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_azure_communication_sms_service.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_azure_communication_sms_service.py index cf3c05b03286..5782b9f7d32a 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_azure_communication_sms_service.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_azure_communication_sms_service.py @@ -25,7 +25,7 @@ class AzureCommunicationSMSService(object): :ivar sms: SmsOperations operations :vartype sms: azure.communication.sms.operations.SmsOperations - :param endpoint: The endpoint of the Azure Communication resource. + :param endpoint: The communication resource, for example https://my-resource.communication.azure.com. :type endpoint: str """ @@ -41,6 +41,7 @@ def __init__( client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False self._deserialize = Deserializer(client_models) self.sms = SmsOperations( diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_configuration.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_configuration.py index 4278d2bdd48a..9d3154a1fa3b 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_configuration.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/_configuration.py @@ -23,7 +23,7 @@ class AzureCommunicationSMSServiceConfiguration(Configuration): Note that all parameters used to create this instance are saved as instance attributes. - :param endpoint: The endpoint of the Azure Communication resource. + :param endpoint: The communication resource, for example https://my-resource.communication.azure.com. :type endpoint: str """ @@ -38,7 +38,7 @@ def __init__( super(AzureCommunicationSMSServiceConfiguration, self).__init__(**kwargs) self.endpoint = endpoint - self.api_version = "2020-07-20-preview1" + self.api_version = "2021-03-07" kwargs.setdefault('sdk_moniker', 'azurecommunicationsmsservice/{}'.format(VERSION)) self._configure(**kwargs) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_azure_communication_sms_service.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_azure_communication_sms_service.py index 81e188e2282b..1a50cb2f24f5 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_azure_communication_sms_service.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_azure_communication_sms_service.py @@ -21,7 +21,7 @@ class AzureCommunicationSMSService(object): :ivar sms: SmsOperations operations :vartype sms: azure.communication.sms.aio.operations.SmsOperations - :param endpoint: The endpoint of the Azure Communication resource. + :param endpoint: The communication resource, for example https://my-resource.communication.azure.com. :type endpoint: str """ @@ -36,6 +36,7 @@ def __init__( client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} self._serialize = Serializer(client_models) + self._serialize.client_side_validation = False self._deserialize = Deserializer(client_models) self.sms = SmsOperations( diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_configuration.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_configuration.py index 4200ab88d62c..77033099353f 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_configuration.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/_configuration.py @@ -19,7 +19,7 @@ class AzureCommunicationSMSServiceConfiguration(Configuration): Note that all parameters used to create this instance are saved as instance attributes. - :param endpoint: The endpoint of the Azure Communication resource. + :param endpoint: The communication resource, for example https://my-resource.communication.azure.com. :type endpoint: str """ @@ -33,7 +33,7 @@ def __init__( super(AzureCommunicationSMSServiceConfiguration, self).__init__(**kwargs) self.endpoint = endpoint - self.api_version = "2020-07-20-preview1" + self.api_version = "2021-03-07" kwargs.setdefault('sdk_moniker', 'azurecommunicationsmsservice/{}'.format(VERSION)) self._configure(**kwargs) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/operations/_sms_operations.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/operations/_sms_operations.py index e291a219e3ee..500c4fa9d9e5 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/operations/_sms_operations.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/aio/operations/_sms_operations.py @@ -12,7 +12,7 @@ from azure.core.pipeline import PipelineResponse from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest -from ... import models +from ... import models as _models T = TypeVar('T') ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -31,7 +31,7 @@ class SmsOperations: :param deserializer: An object model deserializer. """ - models = models + models = _models def __init__(self, client, config, serializer, deserializer) -> None: self._client = client @@ -41,9 +41,9 @@ def __init__(self, client, config, serializer, deserializer) -> None: async def send( self, - send_message_request: "models.SendMessageRequest", + send_message_request: "_models.SendMessageRequest", **kwargs - ) -> "models.SendSmsResponse": + ) -> "_models.SmsSendResponse": """Sends a SMS message from a phone number that belongs to the authenticated account. Sends a SMS message from a phone number that belongs to the authenticated account. @@ -51,16 +51,16 @@ async def send( :param send_message_request: Represents the body of the send message request. :type send_message_request: ~azure.communication.sms.models.SendMessageRequest :keyword callable cls: A custom type or function that will be passed the direct response - :return: SendSmsResponse, or the result of cls(response) - :rtype: ~azure.communication.sms.models.SendSmsResponse + :return: SmsSendResponse, or the result of cls(response) + :rtype: ~azure.communication.sms.models.SmsSendResponse :raises: ~azure.core.exceptions.HttpResponseError """ - cls = kwargs.pop('cls', None) # type: ClsType["models.SendSmsResponse"] + cls = kwargs.pop('cls', None) # type: ClsType["_models.SmsSendResponse"] error_map = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2020-07-20-preview1" + api_version = "2021-03-07" content_type = kwargs.pop("content_type", "application/json") accept = "application/json" @@ -87,11 +87,11 @@ async def send( pipeline_response = await self._client._pipeline.run(request, stream=False, **kwargs) response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [202]: map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) - deserialized = self._deserialize('SendSmsResponse', pipeline_response) + deserialized = self._deserialize('SmsSendResponse', pipeline_response) if cls: return cls(pipeline_response, deserialized, {}) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/__init__.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/__init__.py index e2aafb5fe3ea..74b2447dbed0 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/__init__.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/__init__.py @@ -8,15 +8,26 @@ try: from ._models_py3 import SendMessageRequest - from ._models_py3 import SendSmsOptions - from ._models_py3 import SendSmsResponse + from ._models_py3 import SmsRecipient + from ._models_py3 import SmsSendOptions + from ._models_py3 import SmsSendResponse + from ._models_py3 import SmsSendResponseItem except (SyntaxError, ImportError): from ._models import SendMessageRequest # type: ignore - from ._models import SendSmsOptions # type: ignore - from ._models import SendSmsResponse # type: ignore + from ._models import SmsRecipient # type: ignore + from ._models import SmsSendOptions # type: ignore + from ._models import SmsSendResponse # type: ignore + from ._models import SmsSendResponseItem # type: ignore + +from ._azure_communication_sms_service_enums import ( + SmsSendResponseItemRepeatabilityResult, +) __all__ = [ 'SendMessageRequest', - 'SendSmsOptions', - 'SendSmsResponse', + 'SmsRecipient', + 'SmsSendOptions', + 'SmsSendResponse', + 'SmsSendResponseItem', + 'SmsSendResponseItemRepeatabilityResult', ] diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_azure_communication_sms_service_enums.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_azure_communication_sms_service_enums.py new file mode 100644 index 000000000000..635ce86194d5 --- /dev/null +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_azure_communication_sms_service_enums.py @@ -0,0 +1,35 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum, EnumMeta +from six import with_metaclass + +class _CaseInsensitiveEnumMeta(EnumMeta): + def __getitem__(self, name): + return super().__getitem__(name.upper()) + + def __getattr__(cls, name): + """Return the enum member matching `name` + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + """ + try: + return cls._member_map_[name.upper()] + except KeyError: + raise AttributeError(name) + + +class SmsSendResponseItemRepeatabilityResult(with_metaclass(_CaseInsensitiveEnumMeta, str, Enum)): + """The result of a repeatable request with one of the case-insensitive values accepted or + rejected. + """ + + ACCEPTED = "accepted" + REJECTED = "rejected" diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models.py index 7cb1120b4b3f..5e173280184a 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models.py @@ -17,27 +17,27 @@ class SendMessageRequest(msrest.serialization.Model): :param from_property: Required. The sender's phone number in E.164 format that is owned by the authenticated account. :type from_property: str - :param to: Required. The recipients' phone number in E.164 format. In this version, only one - recipient in the list is supported. - :type to: list[str] + :param sms_recipients: Required. The recipient's phone number in E.164 format. In this version, + a minimum of 1 and upto 100 recipients in the list are supported. + :type sms_recipients: list[~azure.communication.sms.models.SmsRecipient] :param message: Required. The contents of the message that will be sent to the recipient. The allowable content is defined by RFC 5724. :type message: str - :param send_sms_options: Optional configuration for sending SMS messages. - :type send_sms_options: ~azure.communication.sms.models.SendSmsOptions + :param sms_send_options: Optional configuration for sending SMS messages. + :type sms_send_options: ~azure.communication.sms.models.SmsSendOptions """ _validation = { 'from_property': {'required': True}, - 'to': {'required': True}, + 'sms_recipients': {'required': True}, 'message': {'required': True, 'max_length': 2048, 'min_length': 0}, } _attribute_map = { 'from_property': {'key': 'from', 'type': 'str'}, - 'to': {'key': 'to', 'type': '[str]'}, + 'sms_recipients': {'key': 'smsRecipients', 'type': '[SmsRecipient]'}, 'message': {'key': 'message', 'type': 'str'}, - 'send_sms_options': {'key': 'sendSmsOptions', 'type': 'SendSmsOptions'}, + 'sms_send_options': {'key': 'smsSendOptions', 'type': 'SmsSendOptions'}, } def __init__( @@ -46,45 +46,152 @@ def __init__( ): super(SendMessageRequest, self).__init__(**kwargs) self.from_property = kwargs['from_property'] - self.to = kwargs['to'] + self.sms_recipients = kwargs['sms_recipients'] self.message = kwargs['message'] - self.send_sms_options = kwargs.get('send_sms_options', None) + self.sms_send_options = kwargs.get('sms_send_options', None) + + +class SmsRecipient(msrest.serialization.Model): + """Recipient details for sending SMS messages. + All required parameters must be populated in order to send to Azure. + + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, the client can make the request multiple times with the same + Repeatability-Request-ID and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-ID is an opaque string + representing a client-generated, 36-character hexadecimal case-insensitive encoding of a UUID + (GUID), identifier for the request. + :type repeatability_request_id: str + :param repeatability_first_sent: MUST be sent by clients to specify that a request is + repeatable. Repeatability-First-Sent is used to specify the date and time at which the request + was first created.eg- Tue, 26 Mar 2019 16:06:51 GMT. + :type repeatability_first_sent: str + """ -class SendSmsOptions(msrest.serialization.Model): + _validation = { + 'to': {'required': True}, + } + + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, + 'repeatability_request_id': {'key': 'repeatabilityRequestId', 'type': 'str'}, + 'repeatability_first_sent': {'key': 'repeatabilityFirstSent', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SmsRecipient, self).__init__(**kwargs) + self.to = kwargs['to'] + self.repeatability_request_id = kwargs.get('repeatability_request_id', None) + self.repeatability_first_sent = kwargs.get('repeatability_first_sent', None) + + +class SmsSendOptions(msrest.serialization.Model): """Optional configuration for sending SMS messages. - :param enable_delivery_report: Enable this flag to receive a delivery report for this message - on the Azure Resource EventGrid. + All required parameters must be populated in order to send to Azure. + + :param enable_delivery_report: Required. Enable this flag to receive a delivery report for this + message on the Azure Resource EventGrid. :type enable_delivery_report: bool + :param tag: Use this field to provide metadata that will then be sent back in the corresponding + Delivery Report. + :type tag: str """ + _validation = { + 'enable_delivery_report': {'required': True}, + } + _attribute_map = { 'enable_delivery_report': {'key': 'enableDeliveryReport', 'type': 'bool'}, + 'tag': {'key': 'tag', 'type': 'str'}, } def __init__( self, **kwargs ): - super(SendSmsOptions, self).__init__(**kwargs) - self.enable_delivery_report = kwargs.get('enable_delivery_report', None) + super(SmsSendOptions, self).__init__(**kwargs) + self.enable_delivery_report = kwargs['enable_delivery_report'] + self.tag = kwargs.get('tag', None) + +class SmsSendResponse(msrest.serialization.Model): + """Response for a successful or multi status send Sms request. -class SendSmsResponse(msrest.serialization.Model): - """Response for a successful send Sms request. + All required parameters must be populated in order to send to Azure. - :param message_id: The identifier of the outgoing SMS message. + :param value: Required. + :type value: list[~azure.communication.sms.models.SmsSendResponseItem] + """ + + _validation = { + 'value': {'required': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SmsSendResponseItem]'}, + } + + def __init__( + self, + **kwargs + ): + super(SmsSendResponse, self).__init__(**kwargs) + self.value = kwargs['value'] + + +class SmsSendResponseItem(msrest.serialization.Model): + """Response for a single recipient. + + All required parameters must be populated in order to send to Azure. + + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param message_id: The identifier of the outgoing Sms message. Only present if message + processed. :type message_id: str + :param http_status_code: Required. HTTP Status code. + :type http_status_code: int + :param repeatability_result: The result of a repeatable request with one of the case- + insensitive values accepted or rejected. Possible values include: "accepted", "rejected". + :type repeatability_result: str or + ~azure.communication.sms.models.SmsSendResponseItemRepeatabilityResult + :param successful: Required. Indicates if the message is processed successfully or not. + :type successful: bool + :param error_message: Optional error message in case of 4xx/5xx/repeatable errors. + :type error_message: str """ + _validation = { + 'to': {'required': True}, + 'http_status_code': {'required': True}, + 'successful': {'required': True}, + } + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, 'message_id': {'key': 'messageId', 'type': 'str'}, + 'http_status_code': {'key': 'httpStatusCode', 'type': 'int'}, + 'repeatability_result': {'key': 'repeatabilityResult', 'type': 'str'}, + 'successful': {'key': 'successful', 'type': 'bool'}, + 'error_message': {'key': 'errorMessage', 'type': 'str'}, } def __init__( self, **kwargs ): - super(SendSmsResponse, self).__init__(**kwargs) + super(SmsSendResponseItem, self).__init__(**kwargs) + self.to = kwargs['to'] self.message_id = kwargs.get('message_id', None) + self.http_status_code = kwargs['http_status_code'] + self.repeatability_result = kwargs.get('repeatability_result', None) + self.successful = kwargs['successful'] + self.error_message = kwargs.get('error_message', None) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models_py3.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models_py3.py index 03f686209337..e6ad9d3aba20 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models_py3.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/models/_models_py3.py @@ -6,10 +6,12 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import List, Optional +from typing import List, Optional, Union import msrest.serialization +from ._azure_communication_sms_service_enums import * + class SendMessageRequest(msrest.serialization.Model): """Represents the properties of a send message request. @@ -19,83 +21,202 @@ class SendMessageRequest(msrest.serialization.Model): :param from_property: Required. The sender's phone number in E.164 format that is owned by the authenticated account. :type from_property: str - :param to: Required. The recipients' phone number in E.164 format. In this version, only one - recipient in the list is supported. - :type to: list[str] + :param sms_recipients: Required. The recipient's phone number in E.164 format. In this version, + a minimum of 1 and upto 100 recipients in the list are supported. + :type sms_recipients: list[~azure.communication.sms.models.SmsRecipient] :param message: Required. The contents of the message that will be sent to the recipient. The allowable content is defined by RFC 5724. :type message: str - :param send_sms_options: Optional configuration for sending SMS messages. - :type send_sms_options: ~azure.communication.sms.models.SendSmsOptions + :param sms_send_options: Optional configuration for sending SMS messages. + :type sms_send_options: ~azure.communication.sms.models.SmsSendOptions """ _validation = { 'from_property': {'required': True}, - 'to': {'required': True}, + 'sms_recipients': {'required': True}, 'message': {'required': True, 'max_length': 2048, 'min_length': 0}, } _attribute_map = { 'from_property': {'key': 'from', 'type': 'str'}, - 'to': {'key': 'to', 'type': '[str]'}, + 'sms_recipients': {'key': 'smsRecipients', 'type': '[SmsRecipient]'}, 'message': {'key': 'message', 'type': 'str'}, - 'send_sms_options': {'key': 'sendSmsOptions', 'type': 'SendSmsOptions'}, + 'sms_send_options': {'key': 'smsSendOptions', 'type': 'SmsSendOptions'}, } def __init__( self, *, from_property: str, - to: List[str], + sms_recipients: List["SmsRecipient"], message: str, - send_sms_options: Optional["SendSmsOptions"] = None, + sms_send_options: Optional["SmsSendOptions"] = None, **kwargs ): super(SendMessageRequest, self).__init__(**kwargs) self.from_property = from_property - self.to = to + self.sms_recipients = sms_recipients self.message = message - self.send_sms_options = send_sms_options + self.sms_send_options = sms_send_options + + +class SmsRecipient(msrest.serialization.Model): + """Recipient details for sending SMS messages. + + All required parameters must be populated in order to send to Azure. + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param repeatability_request_id: If specified, the client directs that the request is + repeatable; that is, the client can make the request multiple times with the same + Repeatability-Request-ID and get back an appropriate response without the server executing the + request multiple times. The value of the Repeatability-Request-ID is an opaque string + representing a client-generated, 36-character hexadecimal case-insensitive encoding of a UUID + (GUID), identifier for the request. + :type repeatability_request_id: str + :param repeatability_first_sent: MUST be sent by clients to specify that a request is + repeatable. Repeatability-First-Sent is used to specify the date and time at which the request + was first created.eg- Tue, 26 Mar 2019 16:06:51 GMT. + :type repeatability_first_sent: str + """ -class SendSmsOptions(msrest.serialization.Model): + _validation = { + 'to': {'required': True}, + } + + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, + 'repeatability_request_id': {'key': 'repeatabilityRequestId', 'type': 'str'}, + 'repeatability_first_sent': {'key': 'repeatabilityFirstSent', 'type': 'str'}, + } + + def __init__( + self, + *, + to: str, + repeatability_request_id: Optional[str] = None, + repeatability_first_sent: Optional[str] = None, + **kwargs + ): + super(SmsRecipient, self).__init__(**kwargs) + self.to = to + self.repeatability_request_id = repeatability_request_id + self.repeatability_first_sent = repeatability_first_sent + + +class SmsSendOptions(msrest.serialization.Model): """Optional configuration for sending SMS messages. - :param enable_delivery_report: Enable this flag to receive a delivery report for this message - on the Azure Resource EventGrid. + All required parameters must be populated in order to send to Azure. + + :param enable_delivery_report: Required. Enable this flag to receive a delivery report for this + message on the Azure Resource EventGrid. :type enable_delivery_report: bool + :param tag: Use this field to provide metadata that will then be sent back in the corresponding + Delivery Report. + :type tag: str """ + _validation = { + 'enable_delivery_report': {'required': True}, + } + _attribute_map = { 'enable_delivery_report': {'key': 'enableDeliveryReport', 'type': 'bool'}, + 'tag': {'key': 'tag', 'type': 'str'}, } def __init__( self, *, - enable_delivery_report: Optional[bool] = None, + enable_delivery_report: bool, + tag: Optional[str] = None, **kwargs ): - super(SendSmsOptions, self).__init__(**kwargs) + super(SmsSendOptions, self).__init__(**kwargs) self.enable_delivery_report = enable_delivery_report + self.tag = tag + + +class SmsSendResponse(msrest.serialization.Model): + """Response for a successful or multi status send Sms request. + + All required parameters must be populated in order to send to Azure. + + :param value: Required. + :type value: list[~azure.communication.sms.models.SmsSendResponseItem] + """ + + _validation = { + 'value': {'required': True}, + } + + _attribute_map = { + 'value': {'key': 'value', 'type': '[SmsSendResponseItem]'}, + } + + def __init__( + self, + *, + value: List["SmsSendResponseItem"], + **kwargs + ): + super(SmsSendResponse, self).__init__(**kwargs) + self.value = value -class SendSmsResponse(msrest.serialization.Model): - """Response for a successful send Sms request. +class SmsSendResponseItem(msrest.serialization.Model): + """Response for a single recipient. - :param message_id: The identifier of the outgoing SMS message. + All required parameters must be populated in order to send to Azure. + + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param message_id: The identifier of the outgoing Sms message. Only present if message + processed. :type message_id: str + :param http_status_code: Required. HTTP Status code. + :type http_status_code: int + :param repeatability_result: The result of a repeatable request with one of the case- + insensitive values accepted or rejected. Possible values include: "accepted", "rejected". + :type repeatability_result: str or + ~azure.communication.sms.models.SmsSendResponseItemRepeatabilityResult + :param successful: Required. Indicates if the message is processed successfully or not. + :type successful: bool + :param error_message: Optional error message in case of 4xx/5xx/repeatable errors. + :type error_message: str """ + _validation = { + 'to': {'required': True}, + 'http_status_code': {'required': True}, + 'successful': {'required': True}, + } + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, 'message_id': {'key': 'messageId', 'type': 'str'}, + 'http_status_code': {'key': 'httpStatusCode', 'type': 'int'}, + 'repeatability_result': {'key': 'repeatabilityResult', 'type': 'str'}, + 'successful': {'key': 'successful', 'type': 'bool'}, + 'error_message': {'key': 'errorMessage', 'type': 'str'}, } def __init__( self, *, + to: str, + http_status_code: int, + successful: bool, message_id: Optional[str] = None, + repeatability_result: Optional[Union[str, "SmsSendResponseItemRepeatabilityResult"]] = None, + error_message: Optional[str] = None, **kwargs ): - super(SendSmsResponse, self).__init__(**kwargs) + super(SmsSendResponseItem, self).__init__(**kwargs) + self.to = to self.message_id = message_id + self.http_status_code = http_status_code + self.repeatability_result = repeatability_result + self.successful = successful + self.error_message = error_message diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/operations/_sms_operations.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/operations/_sms_operations.py index 162fa238b22c..1f0d0640e125 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/operations/_sms_operations.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_generated/operations/_sms_operations.py @@ -12,7 +12,7 @@ from azure.core.pipeline import PipelineResponse from azure.core.pipeline.transport import HttpRequest, HttpResponse -from .. import models +from .. import models as _models if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports @@ -35,7 +35,7 @@ class SmsOperations(object): :param deserializer: An object model deserializer. """ - models = models + models = _models def __init__(self, client, config, serializer, deserializer): self._client = client @@ -45,10 +45,10 @@ def __init__(self, client, config, serializer, deserializer): def send( self, - send_message_request, # type: "models.SendMessageRequest" + send_message_request, # type: "_models.SendMessageRequest" **kwargs # type: Any ): - # type: (...) -> "models.SendSmsResponse" + # type: (...) -> "_models.SmsSendResponse" """Sends a SMS message from a phone number that belongs to the authenticated account. Sends a SMS message from a phone number that belongs to the authenticated account. @@ -56,16 +56,16 @@ def send( :param send_message_request: Represents the body of the send message request. :type send_message_request: ~azure.communication.sms.models.SendMessageRequest :keyword callable cls: A custom type or function that will be passed the direct response - :return: SendSmsResponse, or the result of cls(response) - :rtype: ~azure.communication.sms.models.SendSmsResponse + :return: SmsSendResponse, or the result of cls(response) + :rtype: ~azure.communication.sms.models.SmsSendResponse :raises: ~azure.core.exceptions.HttpResponseError """ - cls = kwargs.pop('cls', None) # type: ClsType["models.SendSmsResponse"] + cls = kwargs.pop('cls', None) # type: ClsType["_models.SmsSendResponse"] error_map = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError } error_map.update(kwargs.pop('error_map', {})) - api_version = "2020-07-20-preview1" + api_version = "2021-03-07" content_type = kwargs.pop("content_type", "application/json") accept = "application/json" @@ -92,11 +92,11 @@ def send( pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs) response = pipeline_response.http_response - if response.status_code not in [200]: + if response.status_code not in [202]: map_error(status_code=response.status_code, response=response, error_map=error_map) raise HttpResponseError(response=response) - deserialized = self._deserialize('SendSmsResponse', pipeline_response) + deserialized = self._deserialize('SmsSendResponse', pipeline_response) if cls: return cls(pipeline_response, deserialized, {}) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_models/__init__.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/__init__.py new file mode 100644 index 000000000000..96cd579bc6e1 --- /dev/null +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/__init__.py @@ -0,0 +1,16 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import SmsSendResult +except (SyntaxError, ImportError): + from ._models import SmsSendResult # type: ignore + +__all__ = [ + 'SmsSendResult' +] diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models.py new file mode 100644 index 000000000000..c6b703966efe --- /dev/null +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models.py @@ -0,0 +1,53 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import msrest.serialization + + +class SmsSendResult(msrest.serialization.Model): + """Response for a single recipient. + + All required parameters must be populated in order to send to Azure. + + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param message_id: The identifier of the outgoing Sms message. Only present if message + processed. + :type message_id: str + :param http_status_code: Required. HTTP Status code. + :type http_status_code: int + :param successful: Required. Indicates if the message is processed successfully or not. + :type successful: bool + :param error_message: Optional error message in case of 4xx/5xx/repeatable errors. + :type error_message: str + """ + + _validation = { + 'to': {'required': True}, + 'http_status_code': {'required': True}, + 'successful': {'required': True}, + } + + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, + 'message_id': {'key': 'messageId', 'type': 'str'}, + 'http_status_code': {'key': 'httpStatusCode', 'type': 'int'}, + 'successful': {'key': 'successful', 'type': 'bool'}, + 'error_message': {'key': 'errorMessage', 'type': 'str'}, + } + + def __init__( + self, + **kwargs + ): + super(SmsSendResult, self).__init__(**kwargs) + self.to = kwargs['to'] + self.message_id = kwargs.get('message_id', None) + self.http_status_code = kwargs['http_status_code'] + self.successful = kwargs['successful'] + self.error_message = kwargs.get('error_message', None) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models_py3.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models_py3.py new file mode 100644 index 000000000000..cd3d27e53547 --- /dev/null +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_models/_models_py3.py @@ -0,0 +1,61 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Optional + +import msrest.serialization + + +class SmsSendResult(msrest.serialization.Model): + """Response for a single recipient. + + All required parameters must be populated in order to send to Azure. + + :param to: Required. The recipient's phone number in E.164 format. + :type to: str + :param message_id: The identifier of the outgoing Sms message. Only present if message + processed. + :type message_id: str + :param http_status_code: Required. HTTP Status code. + :type http_status_code: int + :param successful: Required. Indicates if the message is processed successfully or not. + :type successful: bool + :param error_message: Optional error message in case of 4xx/5xx/repeatable errors. + :type error_message: str + """ + + _validation = { + 'to': {'required': True}, + 'http_status_code': {'required': True}, + 'successful': {'required': True}, + } + + _attribute_map = { + 'to': {'key': 'to', 'type': 'str'}, + 'message_id': {'key': 'messageId', 'type': 'str'}, + 'http_status_code': {'key': 'httpStatusCode', 'type': 'int'}, + 'successful': {'key': 'successful', 'type': 'bool'}, + 'error_message': {'key': 'errorMessage', 'type': 'str'}, + } + + def __init__( + self, + *, + to: str, + http_status_code: int, + successful: bool, + message_id: Optional[str] = None, + error_message: Optional[str] = None, + **kwargs + ): + super(SmsSendResult, self).__init__(**kwargs) + self.to = to + self.message_id = message_id + self.http_status_code = http_status_code + self.successful = successful + self.error_message = error_message diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_sms_client.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_sms_client.py index 15f06ad9da1c..be0956fc1853 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_sms_client.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_sms_client.py @@ -4,9 +4,15 @@ # license information. # -------------------------------------------------------------------------- +from uuid import uuid4 +from datetime import datetime from azure.core.tracing.decorator import distributed_trace -from azure.communication.sms._generated.models import SendMessageRequest -from azure.communication.sms._generated.models import SendSmsResponse +from azure.communication.sms._generated.models import ( + SendMessageRequest, + SmsRecipient, + SmsSendOptions, +) +from azure.communication.sms._models import SmsSendResult from ._generated._azure_communication_sms_service import AzureCommunicationSMSService from ._shared.utils import parse_connection_str, get_authentication_policy @@ -72,31 +78,58 @@ def from_connection_string(cls, conn_str, # type: str return cls(endpoint, access_key, **kwargs) @distributed_trace - def send(self, from_phone_number, # type: ~azure.communication.sms.PhoneNumberIdentifier - to_phone_numbers, # type: list[~azure.communication.sms.PhoneNumberIdentifier] + def send(self, from_, # type: str + to, # type: Union[str, List[str]] message, # type: str - **kwargs #type: Any - ): # type: (...) -> SendSmsResponse + **kwargs #type: Any + ): # type: (...) -> [SmsSendResult] """Sends SMSs to phone numbers. - :param from_phone_number: the sender of the SMS. - :type from_phone_number: ~azure.communication.sms.PhoneNumberIdentifier - :param to_phone_numbers: the list of recipients of the SMS. - :type to_phone_numbers: list[~azure.communication.sms.PhoneNumberIdentifier] + :param str from_: The sender of the SMS. + :param to: The single recipient or the list of recipients of the SMS. + :type to: Union[str, List[str]] :param str message: The message in the SMS - :keyword send_sms_options: the options object to configure delivery reporting. - :type send_sms_options: ~azure.communication.sms.models.SendSmsOptions - :return: The response object with the message_id - :rtype: SendMessageResponse: ~azure.communication.sms.models.SendMessageResponse + :keyword bool enable_delivery_report: Enable this flag to receive a delivery report for this + message on the Azure Resource EventGrid. + :keyword str tag: Use this field to provide metadata that will then be sent back in the corresponding + Delivery Report. + :return: A list of SmsSendResult. + :rtype: [~azure.communication.sms.models.SmsSendResult] """ - send_sms_options = kwargs.pop('send_sms_options', None) + if isinstance(to, str): + to = [to] + + enable_delivery_report = kwargs.pop('enable_delivery_report', False) + tag = kwargs.pop('tag', None) + + sms_send_options = SmsSendOptions( + enable_delivery_report=enable_delivery_report, + tag=tag + ) request = SendMessageRequest( - from_property=from_phone_number.phone_number, - to=[p.phone_number for p in to_phone_numbers], + from_property=from_, + sms_recipients=[ + SmsRecipient( + to=p, + repeatability_request_id=str(uuid4()), + repeatability_first_sent=datetime.utcnow() + ) for p in to + ], message=message, - send_sms_options=send_sms_options, + sms_send_options=sms_send_options, **kwargs) - return self._sms_service_client.sms.send(request, **kwargs) + return self._sms_service_client.sms.send( + request, + cls=lambda pr, r, e: [ + SmsSendResult( + to=item.to, + message_id=item.message_id, + http_status_code=item.http_status_code, + successful=item.successful, + error_message=item.error_message + ) for item in r.value + ], + **kwargs) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/aio/_sms_client_async.py b/sdk/communication/azure-communication-sms/azure/communication/sms/aio/_sms_client_async.py index 19f59f7dd40e..bdf820701f50 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/aio/_sms_client_async.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/aio/_sms_client_async.py @@ -4,9 +4,15 @@ # license information. # -------------------------------------------------------------------------- +from uuid import uuid4 +from datetime import datetime from azure.core.tracing.decorator_async import distributed_trace_async -from azure.communication.sms._generated.models import SendMessageRequest -from azure.communication.sms._generated.models import SendSmsResponse +from azure.communication.sms._generated.models import ( + SendMessageRequest, + SmsRecipient, + SmsSendOptions, +) +from azure.communication.sms._models import SmsSendResult from .._generated.aio._azure_communication_sms_service import AzureCommunicationSMSService from .._shared.utils import parse_connection_str, get_authentication_policy @@ -73,34 +79,61 @@ def from_connection_string(cls, conn_str, # type: str return cls(endpoint, access_key, **kwargs) @distributed_trace_async() - async def send(self, from_phone_number, # type: ~azure.communication.sms.PhoneNumberIdentifier - to_phone_numbers, # type: list[~azure.communication.sms.PhoneNumberIdentifier] - message, # type: str - **kwargs # type: Any - ): # type: (...) -> SendSmsResponse + async def send(self, from_, # type: str + to, # type: Union[str, List[str]] + message, # type: str + **kwargs # type: Any + ): # type: (...) -> [SmsSendResult] """Sends SMSs to phone numbers. - :param from_phone_number: the sender of the SMS. - :type from_phone_number: ~azure.communication.sms.PhoneNumberIdentifier - :param to_phone_numbers: the list of recipients of the SMS. - :type to_phone_numbers: list[~azure.communication.sms.PhoneNumberIdentifier] + :param str from_: The sender of the SMS. + :param to: The single recipient or the list of recipients of the SMS. + :type to: Union[str, List[str]] :param str message: The message in the SMS - :keyword send_sms_options: the options object to configure delivery reporting. - :type send_sms_options: ~azure.communication.sms.models.SendSmsOptions - :return: The response object with the message_id - :rtype: SendMessageResponse: ~azure.communication.sms.models.SendMessageResponse + :keyword bool enable_delivery_report: Enable this flag to receive a delivery report for this + message on the Azure Resource EventGrid. + :keyword str tag: Use this field to provide metadata that will then be sent back in the corresponding + Delivery Report. + :return: A list of SmsSendResult. + :rtype: [~azure.communication.sms.models.SmsSendResult] """ - send_sms_options = kwargs.pop('send_sms_options', None) + if isinstance(to, str): + to = [to] + + enable_delivery_report = kwargs.pop('enable_delivery_report', False) + tag = kwargs.pop('tag', None) + + sms_send_options = SmsSendOptions( + enable_delivery_report=enable_delivery_report, + tag=tag + ) request = SendMessageRequest( - from_property=from_phone_number.phone_number, - to=[p.phone_number for p in to_phone_numbers], + from_property=from_, + sms_recipients=[ + SmsRecipient( + to=p, + repeatability_request_id=str(uuid4()), + repeatability_first_sent=datetime.utcnow() + ) for p in to + ], message=message, - send_sms_options=send_sms_options, + sms_send_options=sms_send_options, **kwargs) - return await self._sms_service_client.sms.send(request, **kwargs) + return await self._sms_service_client.sms.send( + request, + cls=lambda pr, r, e: [ + SmsSendResult( + to=item.to, + message_id=item.message_id, + http_status_code=item.http_status_code, + successful=item.successful, + error_message=item.error_message + ) for item in r.value + ], + **kwargs) async def __aenter__(self) -> "SMSClient": await self._sms_service_client.__aenter__() diff --git a/sdk/communication/azure-communication-sms/samples/sms_sample.py b/sdk/communication/azure-communication-sms/samples/sms_sample.py index a6a649ca793b..69597b1799b7 100644 --- a/sdk/communication/azure-communication-sms/samples/sms_sample.py +++ b/sdk/communication/azure-communication-sms/samples/sms_sample.py @@ -9,7 +9,8 @@ """ FILE: sms_sample.py DESCRIPTION: - These samples demonstrate sending an sms. + These samples demonstrate sending mutiple sms messages and resending + any failed messages. ///authenticating a client via a connection string USAGE: @@ -17,9 +18,7 @@ """ import sys -from azure.communication.sms import ( - SendSmsOptions, PhoneNumberIdentifier, SmsClient -) +from azure.communication.sms import SmsClient sys.path.append("..") @@ -31,13 +30,31 @@ def send_sms(self): sms_client = SmsClient.from_connection_string(connection_string) # calling send() with sms values - smsresponse = sms_client.send( - from_phone_number=PhoneNumberIdentifier(""), - to_phone_numbers=[PhoneNumberIdentifier("")], + sms_responses = sms_client.send( + from_="", + to=["", "", ""], message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property - - print(smsresponse) + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + failed_recipients = [] + for sms_response in sms_responses: + if (sms_response.successful): + print("Message with message id {} was successful sent to {}" + .format(sms_response.message_id, sms_response.to)) + else: + print("Message failed to send to {} with the status code {} and error: {}" + .format(sms_response.to, sms_response.http_status_code, sms_response.error_message)) + if (sms_response.http_status_code != 400): + failed_recipients.append(sms_response.to) + + # calling send() with failed recipients + sms_responses = sms_client.send( + from_="", + to=failed_recipients, + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property if __name__ == '__main__': sample = SmsSamples() diff --git a/sdk/communication/azure-communication-sms/samples/sms_sample_async.py b/sdk/communication/azure-communication-sms/samples/sms_sample_async.py index 29d958c01a7e..2dcf17c7e7f2 100644 --- a/sdk/communication/azure-communication-sms/samples/sms_sample_async.py +++ b/sdk/communication/azure-communication-sms/samples/sms_sample_async.py @@ -6,24 +6,23 @@ # license information. # -------------------------------------------------------------------------- -import sys -import asyncio -from azure.communication.sms import ( - SendSmsOptions, PhoneNumberIdentifier -) -from azure.communication.sms.aio import SmsClient -sys.path.append("..") - """ FILE: sms_sample_async.py DESCRIPTION: - These samples demonstrate sending an sms asynchronously. + These samples demonstrate sending mutiple sms messages and resending + any failed messages. ///authenticating a client via a connection string USAGE: python sms_sample_async.py """ +import sys +import asyncio +from azure.communication.sms.aio import SmsClient + +sys.path.append("..") + class SmsSamples(object): async def send_sms_async(self): @@ -32,17 +31,39 @@ async def send_sms_async(self): async with sms_client: try: - # calling send() with constructed request object - smsresponse = await sms_client.send( - from_phone_number=PhoneNumberIdentifier(""), - to_phone_numbers=[PhoneNumberIdentifier("")], + # calling send() with sms values + sms_responses = await sms_client.send( + from_="", + to=["", "", ""], message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property except Exception: print(Exception) pass - print(smsresponse) + failed_recipients = [] + for sms_response in sms_responses: + if (sms_response.successful): + print("Message with message id {} was successful sent to {}" + .format(sms_response.message_id, sms_response.to)) + else: + print("Message failed to send to {} with the status code {} and error: {}" + .format(sms_response.to, sms_response.http_status_code, sms_response.error_message)) + if (sms_response.http_status_code != 400): + failed_recipients.append(sms_response.to) + + try: + # calling send() with failed recipients + sms_responses = await sms_client.send( + from_="", + to=failed_recipients, + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + except Exception: + print(Exception) + pass if __name__ == '__main__': sample = SmsSamples() diff --git a/sdk/communication/azure-communication-sms/swagger/SWAGGER.md b/sdk/communication/azure-communication-sms/swagger/SWAGGER.md index 188eb3161203..efbd87cb9a62 100644 --- a/sdk/communication/azure-communication-sms/swagger/SWAGGER.md +++ b/sdk/communication/azure-communication-sms/swagger/SWAGGER.md @@ -15,7 +15,7 @@ autorest SWAGGER.md ### Settings ``` yaml -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8818a603b78a1355ba1647ab9cd4e3354cdc4b69/specification/communication/data-plane/Microsoft.CommunicationServicesSms/preview/2020-07-20-preview1/communicationservicessms.json +input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/83d782b99cb85a9b2f5ef22774584541dd0ff997/specification/communication/data-plane/Microsoft.CommunicationServicesSms/stable/2021-03-07/communicationservicessms.json output-folder: ../azure/communication/sms/_generated namespace: azure.communication.sms no-namespace-folders: true diff --git a/sdk/communication/azure-communication-sms/tests/_shared/testcase.py b/sdk/communication/azure-communication-sms/tests/_shared/testcase.py index 287b1d789c29..a45462eee0d7 100644 --- a/sdk/communication/azure-communication-sms/tests/_shared/testcase.py +++ b/sdk/communication/azure-communication-sms/tests/_shared/testcase.py @@ -52,12 +52,21 @@ def process_response(self, response): return response def _replace_keys(self, body): + def _replace_recursively(obj): + if isinstance(obj, dict): + for key in obj: + if key in self._keys: + obj[key] = self._replacement + else: + _replace_recursively(obj[key]) + elif isinstance(obj, list): + for i in obj: + _replace_recursively(i) + import json try: body = json.loads(body) - for key in self._keys: - if key in body: - body[key] = self._replacement + _replace_recursively(body) except (KeyError, ValueError): return body diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_from_phone_number.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_from_phone_number.yaml new file mode 100644 index 000000000000..26e81794ba98 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_from_phone_number.yaml @@ -0,0 +1,47 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '174' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:46:23 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 400, "errorMessage": "Invalid To phone number format.", "repeatabilityResult": + "notavailable", "successful": false}]}' + headers: + api-supported-versions: + - 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: + - application/json; charset=utf-8 + date: + - Fri, 19 Feb 2021 23:46:22 GMT + ms-cv: + - KrZPD8ayDkeofuM5VxUYRA.0 + request-context: + - appId= + transfer-encoding: + - chunked + x-processing-time: + - 442ms + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_to_phone_number.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_to_phone_number.yaml new file mode 100644 index 000000000000..30f949cf9cd4 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_invalid_to_phone_number.yaml @@ -0,0 +1,47 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '174' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:53:30 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 400, "errorMessage": "Invalid To phone number format.", "repeatabilityResult": + "notavailable", "successful": false}]}' + headers: + api-supported-versions: + - 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: + - application/json; charset=utf-8 + date: + - Fri, 19 Feb 2021 23:53:29 GMT + ms-cv: + - ZSmIhRXZ/ku095wAm8oL0Q.0 + request-context: + - appId= + transfer-encoding: + - chunked + x-processing-time: + - 449ms + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_multiple.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_multiple.yaml new file mode 100644 index 000000000000..3963a2963ef7 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_multiple.yaml @@ -0,0 +1,48 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}, {"to": "sanitized"}], + "message": "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": + true, "tag": "custom-tag"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '196' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:53:31 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}, {"to": "sanitized", "messageId": "sanitized", "httpStatusCode": 202, + "errorMessage": null, "repeatabilityResult": "accepted", "successful": true}]}' + headers: + api-supported-versions: + - 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: + - application/json; charset=utf-8 + date: + - Fri, 19 Feb 2021 23:53:31 GMT + ms-cv: + - zGP+zoxEzEWfEoCv9nxZUg.0 + request-context: + - appId= + transfer-encoding: + - chunked + x-processing-time: + - 864ms + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_phone_number_not_owned.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_phone_number_not_owned.yaml new file mode 100644 index 000000000000..cd85b3577267 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_phone_number_not_owned.yaml @@ -0,0 +1,48 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}, {"to": "sanitized"}], + "message": "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": + true, "tag": "custom-tag"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '196' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:46:25 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}, {"to": "sanitized", "messageId": "sanitized", "httpStatusCode": 202, + "errorMessage": null, "repeatabilityResult": "accepted", "successful": true}]}' + headers: + api-supported-versions: + - 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: + - application/json; charset=utf-8 + date: + - Fri, 19 Feb 2021 23:46:24 GMT + ms-cv: + - QRn5iC0ChkehszEjsw0lPA.0 + request-context: + - appId= + transfer-encoding: + - chunked + x-processing-time: + - 966ms + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_single.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_single.yaml new file mode 100644 index 000000000000..42a254f4252f --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e.test_send_sms_single.yaml @@ -0,0 +1,47 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '172' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:53:32 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}]}' + headers: + api-supported-versions: + - 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: + - application/json; charset=utf-8 + date: + - Fri, 19 Feb 2021 23:53:32 GMT + ms-cv: + - HHBTrB+/bkCxJVnBfHRdcA.0 + request-context: + - appId= + transfer-encoding: + - chunked + x-processing-time: + - 510ms + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async.yaml index 51b14df7e423..13d7ef48afb4 100644 --- a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async.yaml +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async.yaml @@ -1,33 +1,37 @@ interactions: - request: - body: '{"from": "sanitized", "to": "sanitized", "message": "Hello World via SMS", - "sendSmsOptions": {"enableDeliveryReport": true}}' + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' headers: Accept: - application/json Content-Length: - - '132' + - '172' Content-Type: - application/json Date: - - Wed, 20 Jan 2021 18:11:24 GMT + - Fri, 19 Feb 2021 23:53:33 GMT User-Agent: - - azsdk-python-communication-sms/1.0.0b5 Python/3.8.5 (Windows-10-10.0.19041-SP0) + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) x-ms-return-client-request-id: - 'true' method: POST - uri: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1 + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 response: - body: '{"messageId": "sanitized"}' + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}]}' headers: + api-supported-versions: 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 content-type: application/json; charset=utf-8 - date: Wed, 20 Jan 2021 18:11:24 GMT - ms-cv: x7uY4q7a+EmmyTMUW8my+A.0 + date: Fri, 19 Feb 2021 23:53:32 GMT + ms-cv: aukatTugoECOYdRfE0uZrA.0 request-context: appId= transfer-encoding: chunked - x-processing-time: 468ms + x-processing-time: 559ms status: - code: 200 - message: OK - url: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1 + code: 202 + message: Accepted + url: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async_from_managed_identity.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async_from_managed_identity.yaml index d425853c779b..0891c2c7ee95 100644 --- a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async_from_managed_identity.yaml +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_async_from_managed_identity.yaml @@ -1,29 +1,33 @@ interactions: - request: - body: '{"from": "sanitized", "to": "sanitized", "message": "Hello World via SMS", - "sendSmsOptions": {"enableDeliveryReport": true}}' + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' headers: Accept: - application/json Content-Length: - - '132' + - '172' Content-Type: - application/json User-Agent: - - azsdk-python-communication-sms/1.0.0b5 Python/3.8.5 (Windows-10-10.0.19041-SP0) + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) method: POST - uri: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1 + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 response: - body: '{"messageId": "sanitized"}' + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}]}' headers: + api-supported-versions: 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 content-type: application/json; charset=utf-8 - date: Wed, 20 Jan 2021 18:11:27 GMT - ms-cv: 2alAVqPXy0O98kSmG+jzFA.0 + date: Fri, 19 Feb 2021 23:53:34 GMT + ms-cv: YVbyy8ilhUCYHPz1CtyXCg.0 request-context: appId= transfer-encoding: chunked - x-processing-time: 827ms + x-processing-time: 984ms status: - code: 200 - message: OK - url: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1 + code: 202 + message: Accepted + url: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_from_phone_number_async.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_from_phone_number_async.yaml new file mode 100644 index 000000000000..342164912d90 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_from_phone_number_async.yaml @@ -0,0 +1,37 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' + headers: + Accept: + - application/json + Content-Length: + - '174' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:46:29 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 400, "errorMessage": "Invalid To phone number format.", "repeatabilityResult": + "notavailable", "successful": false}]}' + headers: + api-supported-versions: 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: application/json; charset=utf-8 + date: Fri, 19 Feb 2021 23:46:28 GMT + ms-cv: XLQdnhCtfU2LhQparOIUmw.0 + request-context: appId= + transfer-encoding: chunked + x-processing-time: 448ms + status: + code: 202 + message: Accepted + url: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_to_phone_number_async.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_to_phone_number_async.yaml new file mode 100644 index 000000000000..7a9c3848e1a9 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_invalid_to_phone_number_async.yaml @@ -0,0 +1,37 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}], "message": + "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": true, "tag": + "custom-tag"}}' + headers: + Accept: + - application/json + Content-Length: + - '174' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:53:35 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 400, "errorMessage": "Invalid To phone number format.", "repeatabilityResult": + "notavailable", "successful": false}]}' + headers: + api-supported-versions: 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: application/json; charset=utf-8 + date: Fri, 19 Feb 2021 23:53:34 GMT + ms-cv: GdUCMRXUhU2Ugu0aFWmg2g.0 + request-context: appId= + transfer-encoding: chunked + x-processing-time: 370ms + status: + code: 202 + message: Accepted + url: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_multiple_async.yaml b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_multiple_async.yaml new file mode 100644 index 000000000000..2df9bcfe0415 --- /dev/null +++ b/sdk/communication/azure-communication-sms/tests/recordings/test_sms_client_e2e_async.test_send_sms_multiple_async.yaml @@ -0,0 +1,38 @@ +interactions: +- request: + body: '{"from": "sanitized", "smsRecipients": [{"to": "sanitized"}, {"to": "sanitized"}], + "message": "Hello World via SMS", "smsSendOptions": {"enableDeliveryReport": + true, "tag": "custom-tag"}}' + headers: + Accept: + - application/json + Content-Length: + - '196' + Content-Type: + - application/json + Date: + - Fri, 19 Feb 2021 23:53:36 GMT + User-Agent: + - azsdk-python-communication-sms/1.0.0b5 Python/3.9.0 (Windows-10-10.0.19041-SP0) + x-ms-return-client-request-id: + - 'true' + method: POST + uri: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 + response: + body: '{"value": [{"to": "sanitized", "messageId": "sanitized", "httpStatusCode": + 202, "errorMessage": null, "repeatabilityResult": "accepted", "successful": + true}, {"to": "sanitized", "messageId": "sanitized", "httpStatusCode": 202, + "errorMessage": null, "repeatabilityResult": "accepted", "successful": true}]}' + headers: + api-supported-versions: 2020-07-20-preview1, 2020-08-20-preview, 2021-03-07 + content-type: application/json; charset=utf-8 + date: Fri, 19 Feb 2021 23:53:35 GMT + ms-cv: 4aZ8xJa3pU+My8OuXJTm2g.0 + request-context: appId= + transfer-encoding: chunked + x-processing-time: 622ms + status: + code: 202 + message: Accepted + url: https://sanitized.communication.azure.com/sms?api-version=2021-03-07 +version: 1 diff --git a/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e.py b/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e.py index 2c4e3d3cc322..3b8020bccdf1 100644 --- a/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e.py +++ b/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e.py @@ -6,9 +6,7 @@ import os import pytest -from azure.communication.sms import ( - PhoneNumberIdentifier, SendSmsOptions, SmsClient -) +from azure.communication.sms import SmsClient from _shared.testcase import ( CommunicationTestCase, BodyReplacerProcessor, @@ -34,13 +32,76 @@ def setUp(self): self.sms_client = SmsClient.from_connection_string(self.connection_str) @pytest.mark.live_test_only - def test_send_sms(self): + def test_send_sms_single(self): + + # calling send() with sms values + sms_responses = self.sms_client.send( + from_=self.phone_number, + to=self.phone_number, + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 1 + + for sms_response in sms_responses: + self.verify_sms_response(sms_response) + + @pytest.mark.live_test_only + def test_send_sms_multiple(self): + + # calling send() with sms values + sms_responses = self.sms_client.send( + from_=self.phone_number, + to=[self.phone_number, self.phone_number], + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 2 + + for sms_response in sms_responses: + self.verify_sms_response(sms_response) + + @pytest.mark.live_test_only + def test_send_sms_invalid_to_phone_number(self): # calling send() with sms values - sms_response = self.sms_client.send( - from_phone_number=PhoneNumberIdentifier(self.phone_number), - to_phone_numbers=[PhoneNumberIdentifier(self.phone_number)], + sms_responses = self.sms_client.send( + from_=self.phone_number, + to=["+1234567891011"], message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 1 + + for sms_response in sms_responses: + assert sms_response.http_status_code == 400 + assert not sms_response.successful + + @pytest.mark.live_test_only + def test_send_sms_unique_message_ids(self): + + # calling send() with sms values + sms_responses_1 = self.sms_client.send( + from_=self.phone_number, + to=[self.phone_number], + message="Hello World via SMS") + + # calling send() again with the same sms values + sms_responses_2 = self.sms_client.send( + from_=self.phone_number, + to=[self.phone_number], + message="Hello World via SMS") + + # message ids should be unique due to having a different idempotency key + assert sms_responses_1[0].message_id != sms_responses_2[0].message_id + def verify_sms_response(self, sms_response): + assert sms_response.to == self.phone_number assert sms_response.message_id is not None + assert sms_response.http_status_code == 202 + assert sms_response.error_message is None + assert sms_response.successful + \ No newline at end of file diff --git a/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e_async.py b/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e_async.py index 4543ccc909fe..31a77793bb2a 100644 --- a/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e_async.py +++ b/sdk/communication/azure-communication-sms/tests/test_sms_client_e2e_async.py @@ -8,9 +8,6 @@ import pytest from azure.core.credentials import AccessToken from azure.communication.sms.aio import SmsClient -from azure.communication.sms import ( - PhoneNumberIdentifier, SendSmsOptions -) from azure.communication.sms._shared.utils import parse_connection_str from _shared.asynctestcase import AsyncCommunicationTestCase from _shared.testcase import ( @@ -18,13 +15,13 @@ ) from azure.identity import DefaultAzureCredential - class FakeTokenCredential(object): def __init__(self): self.token = AccessToken("Fake Token", 0) def get_token(self, *args): return self.token + class SMSClientTestAsync(AsyncCommunicationTestCase): def __init__(self, method_name): super(SMSClientTestAsync, self).__init__(method_name) @@ -43,19 +40,43 @@ def setUp(self): @AsyncCommunicationTestCase.await_prepared_test @pytest.mark.live_test_only - async def test_send_sms_async(self): + async def test_send_sms_single_async(self): sms_client = SmsClient.from_connection_string(self.connection_str) async with sms_client: # calling send() with sms values - sms_response = await sms_client.send( - from_phone_number=PhoneNumberIdentifier(self.phone_number), - to_phone_numbers=[PhoneNumberIdentifier(self.phone_number)], + sms_responses = await sms_client.send( + from_=self.phone_number, + to=self.phone_number, message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 1 + + for sms_response in sms_responses: + self.verify_sms_response(sms_response) + + @AsyncCommunicationTestCase.await_prepared_test + @pytest.mark.live_test_only + async def test_send_sms_multiple_async(self): - assert sms_response.message_id is not None + sms_client = SmsClient.from_connection_string(self.connection_str) + + async with sms_client: + # calling send() with sms values + sms_responses = await sms_client.send( + from_=self.phone_number, + to=[self.phone_number, self.phone_number], + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 2 + + for sms_response in sms_responses: + self.verify_sms_response(sms_response) @AsyncCommunicationTestCase.await_prepared_test @pytest.mark.live_test_only @@ -67,13 +88,67 @@ async def test_send_sms_async_from_managed_identity(self): else: credential = DefaultAzureCredential() sms_client = SmsClient(endpoint, credential) - print(sms_client) + async with sms_client: # calling send() with sms values - sms_response = await sms_client.send( - from_phone_number=PhoneNumberIdentifier(self.phone_number), - to_phone_numbers=[PhoneNumberIdentifier(self.phone_number)], + sms_responses = await sms_client.send( + from_=self.phone_number, + to=[self.phone_number], message="Hello World via SMS", - send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 1 - assert sms_response.message_id is not None + for sms_response in sms_responses: + self.verify_sms_response(sms_response) + + @AsyncCommunicationTestCase.await_prepared_test + @pytest.mark.live_test_only + async def test_send_sms_invalid_to_phone_number_async(self): + + sms_client = SmsClient.from_connection_string(self.connection_str) + + async with sms_client: + # calling send() with sms values + sms_responses = await sms_client.send( + from_=self.phone_number, + to=["+1234567891011"], + message="Hello World via SMS", + enable_delivery_report=True, # optional property + tag="custom-tag") # optional property + + assert len(sms_responses) is 1 + + for sms_response in sms_responses: + assert sms_response.http_status_code == 400 + assert not sms_response.successful + + @AsyncCommunicationTestCase.await_prepared_test + @pytest.mark.live_test_only + async def test_send_sms_unique_message_ids_async(self): + + sms_client = SmsClient.from_connection_string(self.connection_str) + + async with sms_client: + # calling send() with sms values + sms_responses_1 = await sms_client.send( + from_=self.phone_number, + to=[self.phone_number], + message="Hello World via SMS") + + # calling send() again with the same sms values + sms_responses_2 = await sms_client.send( + from_=self.phone_number, + to=[self.phone_number], + message="Hello World via SMS") + + assert sms_responses_1[0].message_id != sms_responses_2[0].message_id + + def verify_sms_response(self, sms_response): + assert sms_response.to == self.phone_number + assert sms_response.message_id is not None + assert sms_response.http_status_code == 202 + assert sms_response.error_message is None + assert sms_response.successful + \ No newline at end of file