Skip to content

Commit

Permalink
[Communication]: SMS 1:N Messages, Custom Tags, and Idempotence (#16836)
Browse files Browse the repository at this point in the history
* Updated SMS clients with new swagger

* Updated SMS client tests

* Updated SMS samples

* Added resending failed messages to SMS samples

* Updated SMS clients to latest swagger

* Updated SMS client tests and recordings

* Updated SMS samples with changes from new swagger

* Added more test cases

* Rebased README file

* Fixed pylint issues

* Added Idempotence Parameters

* Updated SWAGGER formatting

* Added custom SendMessageRequest model to rename the smsSendOptions field to sendSmsOptions

* Updated SMS options parameter

* Hide repeatability_result from SmsSendResult

* Updated failure message in SMS samples

* Updated formatting in models file

* Updated SmsSendResult

* Refactored SmsSendResult

* Fixed pylint issue

* Updated CHANGELOG

* Use UTC time zone for repeatability_first_sent

* Cleaned up CHANGELOG

* Updated SMS samples

* Updated SmsSendOptions

* Add test for idempotency

* Added case when single recipient phone number is a string

* Updated method documentation in SMS clients
  • Loading branch information
lsundaralingam authored Mar 2, 2021
1 parent 5d5d5e0 commit e1b84af
Show file tree
Hide file tree
Showing 34 changed files with 1,233 additions and 212 deletions.
11 changes: 11 additions & 0 deletions sdk/communication/azure-communication-sms/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
29 changes: 18 additions & 11 deletions sdk/communication/azure-communication-sms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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("<leased-phone-number>"),
to_phone_number=[PhoneNumberIdentifier("<to-phone-number>")],
to_phone_numbers=["<to-phone-number-1>", "<to-phone-number-2>", "<to-phone-number-3>"],
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).
Expand All @@ -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 [[email protected]](mailto:[email protected]) with any additional questions or comments.
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.

<!-- LINKS -->
[azure_core]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/core/azure-core/README.md
Original file line number Diff line number Diff line change
@@ -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',
]
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""

Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""

Expand All @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""

Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""

Expand All @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand All @@ -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
Expand All @@ -41,26 +41,26 @@ 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.
: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"

Expand All @@ -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, {})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
]
Original file line number Diff line number Diff line change
@@ -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"
Loading

0 comments on commit e1b84af

Please sign in to comment.