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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# pylint: skip-file

from enum import Enum, EnumMeta
import re
from six import with_metaclass
from typing import Mapping, Optional, Union, Any
try:
Expand Down Expand Up @@ -68,7 +67,7 @@ class CommunicationUserIdentifier(object):

def __init__(self, id, **kwargs):
# type: (str, Any) -> None
self.raw_id = kwargs.get('raw_id', id)
self.raw_id = kwargs.get('raw_id')
self.properties = CommunicationUserProperties(id=id)


Expand Down Expand Up @@ -96,19 +95,6 @@ def __init__(self, value, **kwargs):
# type: (str, Any) -> None
self.raw_id = kwargs.get('raw_id')
self.properties = PhoneNumberProperties(value=value)
if self.raw_id is None:
self.raw_id = _phone_number_raw_id(self)


_PHONE_NUMBER_PREFIX = re.compile(r'^\+')


def _phone_number_raw_id(identifier):
# type (PhoneNumberIdentifier) -> str
value = identifier.properties['value']
# strip the leading +. We just assume correct E.164 format here because
# validation should only happen server-side, not client-side.
return '4:{}'.format(_PHONE_NUMBER_PREFIX.sub('', value))


class UnknownIdentifier(object):
Expand Down Expand Up @@ -168,72 +154,3 @@ def __init__(self, user_id, **kwargs):
is_anonymous=kwargs.get('is_anonymous', False),
cloud=kwargs.get('cloud') or CommunicationCloudEnvironment.PUBLIC
)
if self.raw_id is None:
self.raw_id = _microsoft_teams_user_raw_id(self)


def _microsoft_teams_user_raw_id(identifier):
# type (MicrosoftTeamsUserIdentifier) -> str
user_id = identifier.properties['user_id']
if identifier.properties['is_anonymous']:
return '8:teamsvisitor:{}'.format(user_id)
cloud = identifier.properties['cloud']
if cloud == CommunicationCloudEnvironment.DOD:
return '8:dod:{}'.format(user_id)
elif cloud == CommunicationCloudEnvironment.GCCH:
return '8:gcch:{}'.format(user_id)
elif cloud == CommunicationCloudEnvironment.PUBLIC:
return '8:orgid:{}'.format(user_id)
return '8:orgid:{}'.format(user_id)


def identifier_from_raw_id(raw_id):
"""
Creates a CommunicationIdentifier from a given raw ID.

When storing raw IDs use this function to restore the identifier that was encoded in the raw ID.

:param raw ID to construct the CommunicationIdentifier from.
"""
# type (str) -> CommunicationIdentifier
if raw_id.startswith('4:'):
return PhoneNumberIdentifier(
value='+{}'.format(raw_id[len('4:'):])
)

segments = raw_id.split(':', maxsplit=2)
if len(segments) < 3:
return UnknownIdentifier(identifier=raw_id)

prefix = '{}:{}:'.format(segments[0], segments[1])
suffix = raw_id[len(prefix):]
if prefix == '8:teamsvisitor:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=True
)
elif prefix == '8:orgid:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='PUBLIC'
)
elif prefix == '8:dod:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='DOD'
)
elif prefix == '8:gcch:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='GCCH'
)
elif prefix in ['8:acs:', '8:spool:', '8:dod-acs:', '8:gcch-acs:']:
return CommunicationUserIdentifier(
id=raw_id
)
return UnknownIdentifier(
identifier=raw_id
)
14 changes: 4 additions & 10 deletions sdk/communication/azure-communication-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
# Release History

## 1.1.0 (Unreleased)
## 1.1.0 (2022-08-01)

### Features Added

- Added support to build a custom Teams endpoint using Microsoft 365 Teams identities:
- Added support to integrate communication as Teams user with Azure Communication Services:
- Added `get_token_for_teams_user(aad_token, client_id, user_object_id)` method that provides the ability to exchange an Azure AD access token of a Teams user for a Communication Identity access token to `CommunicationIdentityClient`.
- Removed `ApiVersion.V2021_10_31_preview` from API versions.
- Added a new API version `ApiVersion.V2022_06_01` that is now the deafult API version
- Exported types `MicrosoftTeamsUserIdentifier`, `PhoneNumberIdentifier`, `UnknownIdentifier` for non Azure Communication Services `CommunicationIdentifier` identities.
- Added `identifier_from_raw_id` and ensured that `CommunicationIdentifier.raw_id` is populated on creation. Together, these can be used to translate between a `CommunicationIdentifier` and its underlying canonical raw ID representation. Developers can now use the raw ID as an encoded format for identifiers to store in their databases or as stable keys in general.

### Breaking Changes

### Bugs Fixed
- Added a new API version `ApiVersion.V2022_06_01` that is now the default API version

### Other Changes
- Python 2.7 is no longer supported. Please use Python version 3.7 or later. For more details, please read our page on [Azure SDK for Python version support policy](https://github.com/Azure/azure-sdk-for-python/wiki/Azure-SDKs-Python-version-support-policy).
Expand All @@ -22,7 +16,7 @@

### Features Added

- Added support for Microsoft 365 Teams identities
- Added support to integrate communication as Teams user with Azure Communication Services:
- `CommunicationIdentityClient` added a new method `get_token_for_teams_user` that provides the ability to exchange an Azure AD access token of a Teams user for a Communication Identity access token

## 1.0.1 (2021-06-08)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@
CommunicationIdentifier,
CommunicationIdentifierKind,
CommunicationUserIdentifier,
CommunicationUserProperties,
MicrosoftTeamsUserIdentifier,
PhoneNumberIdentifier,
UnknownIdentifier,
identifier_from_raw_id
CommunicationUserProperties
)

__all__ = [
Expand All @@ -31,9 +27,5 @@
'CommunicationIdentifier',
'CommunicationIdentifierKind',
'CommunicationUserIdentifier',
'CommunicationUserProperties',
'MicrosoftTeamsUserIdentifier',
'PhoneNumberIdentifier',
'UnknownIdentifier',
'identifier_from_raw_id'
'CommunicationUserProperties'
]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# pylint: skip-file

from enum import Enum, EnumMeta
import re
from six import with_metaclass
from typing import Mapping, Optional, Union, Any
try:
Expand Down Expand Up @@ -68,7 +67,7 @@ class CommunicationUserIdentifier(object):

def __init__(self, id, **kwargs):
# type: (str, Any) -> None
self.raw_id = kwargs.get('raw_id', id)
self.raw_id = kwargs.get('raw_id')
self.properties = CommunicationUserProperties(id=id)


Expand Down Expand Up @@ -96,19 +95,6 @@ def __init__(self, value, **kwargs):
# type: (str, Any) -> None
self.raw_id = kwargs.get('raw_id')
self.properties = PhoneNumberProperties(value=value)
if self.raw_id is None:
self.raw_id = _phone_number_raw_id(self)


_PHONE_NUMBER_PREFIX = re.compile(r'^\+')


def _phone_number_raw_id(identifier):
# type (PhoneNumberIdentifier) -> str
value = identifier.properties['value']
# strip the leading +. We just assume correct E.164 format here because
# validation should only happen server-side, not client-side.
return '4:{}'.format(_PHONE_NUMBER_PREFIX.sub('', value))


class UnknownIdentifier(object):
Expand Down Expand Up @@ -168,72 +154,3 @@ def __init__(self, user_id, **kwargs):
is_anonymous=kwargs.get('is_anonymous', False),
cloud=kwargs.get('cloud') or CommunicationCloudEnvironment.PUBLIC
)
if self.raw_id is None:
self.raw_id = _microsoft_teams_user_raw_id(self)


def _microsoft_teams_user_raw_id(identifier):
# type (MicrosoftTeamsUserIdentifier) -> str
user_id = identifier.properties['user_id']
if identifier.properties['is_anonymous']:
return '8:teamsvisitor:{}'.format(user_id)
cloud = identifier.properties['cloud']
if cloud == CommunicationCloudEnvironment.DOD:
return '8:dod:{}'.format(user_id)
elif cloud == CommunicationCloudEnvironment.GCCH:
return '8:gcch:{}'.format(user_id)
elif cloud == CommunicationCloudEnvironment.PUBLIC:
return '8:orgid:{}'.format(user_id)
return '8:orgid:{}'.format(user_id)


def identifier_from_raw_id(raw_id):
"""
Creates a CommunicationIdentifier from a given raw ID.

When storing raw IDs use this function to restore the identifier that was encoded in the raw ID.

:param raw ID to construct the CommunicationIdentifier from.
"""
# type (str) -> CommunicationIdentifier
if raw_id.startswith('4:'):
return PhoneNumberIdentifier(
value='+{}'.format(raw_id[len('4:'):])
)

segments = raw_id.split(':', maxsplit=2)
if len(segments) < 3:
return UnknownIdentifier(identifier=raw_id)

prefix = '{}:{}:'.format(segments[0], segments[1])
suffix = raw_id[len(prefix):]
if prefix == '8:teamsvisitor:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=True
)
elif prefix == '8:orgid:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='PUBLIC'
)
elif prefix == '8:dod:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='DOD'
)
elif prefix == '8:gcch:':
return MicrosoftTeamsUserIdentifier(
user_id=suffix,
is_anonymous=False,
cloud='GCCH'
)
elif prefix in ['8:acs:', '8:spool:', '8:dod-acs:', '8:gcch-acs:']:
return CommunicationUserIdentifier(
id=raw_id
)
return UnknownIdentifier(
identifier=raw_id
)
2 changes: 1 addition & 1 deletion sdk/communication/azure-communication-identity/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
license='MIT License',
# ensure that the development status reflects the status of your package
classifiers=[
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",

'Programming Language :: Python',
'Programming Language :: Python :: 3 :: Only',
Expand Down
Loading