From e682f38f3497c360e078148046676225c8ffacf5 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 11:38:50 -0800 Subject: [PATCH 1/8] saving unit tests so far --- .../core/teams/teams_activity_handler.py | 43 ++-- .../teams/test_teams_activity_handler.py | 217 ++++++++++++++---- .../botbuilder/schema/_models.py | 2 +- .../botbuilder/schema/_models_py3.py | 6 +- .../botbuilder/schema/teams/_models.py | 7 +- .../botbuilder/schema/teams/_models_py3.py | 14 +- 6 files changed, 217 insertions(+), 72 deletions(-) diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py index 04d7389aa..218f6c714 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -12,7 +12,8 @@ TeamsChannelAccount, ) from botframework.connector import Channels - +import json +from typing import List class TeamsActivityHandler(ActivityHandler): async def on_turn(self, turn_context: TurnContext): @@ -261,9 +262,9 @@ async def on_teams_task_module_submit_activity( # pylint: disable=unused-argume raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_conversation_update_activity(self, turn_context: TurnContext): + if turn_context.activity.channel_id == Channels.ms_teams: channel_data = TeamsChannelData(**turn_context.activity.channel_data) - if turn_context.activity.members_added: return await self.on_teams_members_added_dispatch_activity( turn_context.activity.members_added, channel_data.team, turn_context @@ -277,22 +278,20 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): ) if channel_data: - if channel_data.event_type == "channelCreated": + if channel_data.eventType == "channelCreated": return await self.on_teams_channel_created_activity( - channel_data.channel, channel_data.team, turn_context + ChannelInfo(**channel_data.channel), channel_data.team, turn_context ) - if channel_data.event_type == "channelDeleted": + if channel_data.eventType == "channelDeleted": return await self.on_teams_channel_deleted_activity( channel_data.channel, channel_data.team, turn_context ) - if channel_data.event_type == "channelRenamed": + if channel_data.eventType == "channelRenamed": return await self.on_teams_channel_renamed_activity( channel_data.channel, channel_data.team, turn_context ) - if channel_data.event_type == "teamRenamed": - return await self.on_teams_team_renamed_activity( - channel_data.team, turn_context - ) + if channel_data.eventType == "teamRenamed": + return await self.on_teams_team_renamed_activity(channel_data.team, turn_context) return await super().on_conversation_update_activity(turn_context) return await super().on_conversation_update_activity(turn_context) @@ -300,7 +299,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): async def on_teams_channel_created_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): - return + return async def on_teams_team_renamed_activity( # pylint: disable=unused-argument self, team_info: TeamInfo, turn_context: TurnContext @@ -337,17 +336,20 @@ async def on_teams_members_added_dispatch_activity( # pylint: disable=unused-ar return await self.on_teams_members_added_activity(teams_members_added, team_info, turn_context) """ + team_accounts_added = [] for member in members_added: - new_account_json = member.seralize() - del new_account_json["additional_properties"] + new_account_json = member.serialize() + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] member = TeamsChannelAccount(**new_account_json) - return await self.on_teams_members_added_activity(members_added, turn_context) + team_accounts_added.append(member) + return await self.on_teams_members_added_activity(team_accounts_added, turn_context) async def on_teams_members_added_activity( self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext ): - teams_members_added = [ChannelAccount(member) for member in teams_members_added] - return super().on_members_added_activity(teams_members_added, turn_context) + teams_members_added = [ ChannelAccount(**member.serialize()) for member in teams_members_added ] + return await super().on_members_added_activity(teams_members_added, turn_context) async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused-argument self, @@ -357,8 +359,9 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- ): teams_members_removed = [] for member in members_removed: - new_account_json = member.seralize() - del new_account_json["additional_properties"] + new_account_json = member.serialize() + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] teams_members_removed.append(TeamsChannelAccount(**new_account_json)) return await self.on_teams_members_removed_activity( @@ -368,8 +371,8 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- async def on_teams_members_removed_activity( self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext ): - members_removed = [ChannelAccount(member) for member in teams_members_removed] - return super().on_members_removed_activity(members_removed, turn_context) + members_removed = [ChannelAccount(**member.serialize()) for member in teams_members_removed] + return await super().on_members_removed_activity(members_removed, turn_context) async def on_teams_channel_deleted_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 87b092e09..2b04c1f09 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -11,44 +11,36 @@ MessageReaction, ResourceResponse, ) - +from botbuilder.schema.teams import ( + ChannelInfo, + NotificationInfo, + TeamInfo, + TeamsChannelAccount, + TeamsChannelData, + TenantInfo, +) +from botframework.connector import Channels class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): self.record: List[str] = [] + async def on_conversation_update_activity(self, turn_context: TurnContext): + self.record.append("on_conversation_update_activity") + return await super().on_conversation_update_activity(turn_context) + + async def on_teams_members_added_activity(self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_added_activity") + return await super().on_teams_members_added_activity(teams_members_added, turn_context) + + async def on_teams_members_removed_activity(self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_removed_activity") + return await super().on_teams_members_removed_activity(teams_members_removed, turn_context) + async def on_message_activity(self, turn_context: TurnContext): self.record.append("on_message_activity") return await super().on_message_activity(turn_context) - async def on_members_added_activity( - self, members_added: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_added_activity") - return await super().on_members_added_activity(members_added, turn_context) - - async def on_members_removed_activity( - self, members_removed: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_removed_activity") - return await super().on_members_removed_activity(members_removed, turn_context) - - async def on_message_reaction_activity(self, turn_context: TurnContext): - self.record.append("on_message_reaction_activity") - return await super().on_message_reaction_activity(turn_context) - - async def on_reactions_added( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_added") - return await super().on_reactions_added(message_reactions, turn_context) - - async def on_reactions_removed( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_removed") - return await super().on_reactions_removed(message_reactions, turn_context) - async def on_token_response_event(self, turn_context: TurnContext): self.record.append("on_token_response_event") return await super().on_token_response_event(turn_context) @@ -60,7 +52,32 @@ async def on_event(self, turn_context: TurnContext): async def on_unrecognized_activity_type(self, turn_context: TurnContext): self.record.append("on_unrecognized_activity_type") return await super().on_unrecognized_activity_type(turn_context) + + async def on_teams_channel_created_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_created_activity") + return await super().on_teams_channel_created_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_renamed_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_renamed_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_deleted_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_deleted_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_team_renamed_activity(self, team_info: TeamInfo, turn_context: TurnContext): + self.record.append("on_teams_team_renamed_activity") + return await super().on_teams_team_renamed_activity(team_info, turn_context) + async def on_invoke_activity(self, turn_context: TurnContext): + self.record.append("on_invoke_activity") + return await super().on_invoke_activity(turn_context) class NotImplementedAdapter(BotAdapter): async def delete_activity( @@ -76,18 +93,140 @@ async def send_activities( async def update_activity(self, context: TurnContext, activity: Activity): raise NotImplementedError() - class TestTeamsActivityHandler(aiounittest.AsyncTestCase): - async def test_message_reaction(self): - # Note the code supports multiple adds and removes in the same activity though - # a channel may decide to send separate activities for each. For example, Teams - # sends separate activities each with a single add and a single remove. + async def test_on_teams_channel_created_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelCreated", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_created_activity" + + async def test_on_teams_channel_renamed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelRenamed", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) - # Arrange + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_renamed_activity" + + async def test_on_teams_channel_deleted_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelDeleted", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_deleted_activity" + + async def test_on_teams_team_renamed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamRenamed", + "team": { + "id": "team_id_1", + "name" : "new_team_name" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_team_renamed_activity" + + async def test_on_teams_members_added_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberAdded" + }, + members_added = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_added_activity" + + async def test_on_teams_members_removed_activity(self): + #arrange activity = Activity( - type=ActivityTypes.message_reaction, - reactions_added=[MessageReaction(type="sad")], + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberRemoved" + }, + members_removed = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams ) + turn_context = TurnContext(NotImplementedAdapter(), activity) # Act @@ -96,5 +235,5 @@ async def test_message_reaction(self): # Assert assert len(bot.record) == 2 - assert bot.record[0] == "on_message_reaction_activity" - assert bot.record[1] == "on_reactions_added" + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_removed_activity" \ No newline at end of file diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models.py b/libraries/botbuilder-schema/botbuilder/schema/_models.py index 736ddcf81..dc40b3fee 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models.py @@ -611,7 +611,7 @@ def __init__(self, **kwargs): super(ChannelAccount, self).__init__(**kwargs) self.id = kwargs.get("id", None) self.name = kwargs.get("name", None) - self.aad_object_id = kwargs.get("aad_object_id", None) + self.aadObjectId = kwargs.get("aadObjectId", None) self.role = kwargs.get("role", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index 58caa1567..c6cd5fdba 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -721,7 +721,7 @@ class ChannelAccount(Model): _attribute_map = { "id": {"key": "id", "type": "str"}, "name": {"key": "name", "type": "str"}, - "aad_object_id": {"key": "aadObjectId", "type": "str"}, + "aadObjectId": {"key": "aadObjectId", "type": "str"}, "role": {"key": "role", "type": "str"}, } @@ -730,14 +730,14 @@ def __init__( *, id: str = None, name: str = None, - aad_object_id: str = None, + aadObjectId: str = None, role=None, **kwargs ) -> None: super(ChannelAccount, self).__init__(**kwargs) self.id = id self.name = name - self.aad_object_id = aad_object_id + self.aadObjectId = aadObjectId self.role = role diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py index 5e41c6fd4..fe0e5d741 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py @@ -1535,7 +1535,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__(self, **kwargs): @@ -1543,7 +1543,7 @@ def __init__(self, **kwargs): self.given_name = kwargs.get("given_name", None) self.surname = kwargs.get("surname", None) self.email = kwargs.get("email", None) - self.user_principal_name = kwargs.get("user_principal_name", None) + self.userPrincipalName = kwargs.get("userPrincipalName", None) class TeamsChannelData(Model): @@ -1573,7 +1573,8 @@ class TeamsChannelData(Model): def __init__(self, **kwargs): super(TeamsChannelData, self).__init__(**kwargs) self.channel = kwargs.get("channel", None) - self.event_type = kwargs.get("event_type", None) + # doing camel case here since that's how the data comes in + self.eventType = kwargs.get("eventType", None) self.team = kwargs.get("team", None) self.notification = kwargs.get("notification", None) self.tenant = kwargs.get("tenant", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 80249f277..3cd336941 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -1796,7 +1796,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__( @@ -1807,14 +1807,15 @@ def __init__( given_name: str = None, surname: str = None, email: str = None, - user_principal_name: str = None, + userPrincipalName: str = None, **kwargs ) -> None: super(TeamsChannelAccount, self).__init__(id=id, name=name, **kwargs) self.given_name = given_name self.surname = surname self.email = email - self.user_principal_name = user_principal_name + # changing to camel case due to how data comes in off the wire + self.userPrincipalName = userPrincipalName class TeamsChannelData(Model): @@ -1835,7 +1836,7 @@ class TeamsChannelData(Model): _attribute_map = { "channel": {"key": "channel", "type": "ChannelInfo"}, - "event_type": {"key": "eventType", "type": "str"}, + "eventType": {"key": "eventType", "type": "str"}, "team": {"key": "team", "type": "TeamInfo"}, "notification": {"key": "notification", "type": "NotificationInfo"}, "tenant": {"key": "tenant", "type": "TenantInfo"}, @@ -1845,7 +1846,7 @@ def __init__( self, *, channel=None, - event_type: str = None, + eventType: str = None, team=None, notification=None, tenant=None, @@ -1853,7 +1854,8 @@ def __init__( ) -> None: super(TeamsChannelData, self).__init__(**kwargs) self.channel = channel - self.event_type = event_type + # doing camel case here since that's how the data comes in + self.eventType = eventType self.team = team self.notification = notification self.tenant = tenant From aca5c976e93edc601e1219edb222c9105142b670 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 17:13:49 -0800 Subject: [PATCH 2/8] adding unit tests for activity handler, cleaning up types on activity handler --- .../core/teams/teams_activity_handler.py | 84 ++- libraries/botbuilder-core/tests/__init__.py | 3 + .../botbuilder-core/tests/teams/__init__.py | 0 .../teams/test_teams_activity_handler.py | 693 +++++++++++++++++- .../botbuilder/schema/_models.py | 2 +- .../botbuilder/schema/_models_py3.py | 4 +- .../botbuilder/schema/teams/_models.py | 12 +- .../botbuilder/schema/teams/_models_py3.py | 21 +- 8 files changed, 726 insertions(+), 93 deletions(-) create mode 100644 libraries/botbuilder-core/tests/__init__.py create mode 100644 libraries/botbuilder-core/tests/teams/__init__.py diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py index 7ff3cf4ec..8e647b76f 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -6,13 +6,21 @@ from botbuilder.core.turn_context import TurnContext from botbuilder.core import ActivityHandler, InvokeResponse, BotFrameworkAdapter from botbuilder.schema.teams import ( + AppBasedLinkQuery, TeamInfo, ChannelInfo, + FileConsentCardResponse, TeamsChannelData, TeamsChannelAccount, + MessageActionsPayload, + MessagingExtensionAction, + MessagingExtensionQuery, + O365ConnectorCardActionQuery, + TaskModuleRequest ) from botframework.connector import Channels - +import json +from typing import List class TeamsActivityHandler(ActivityHandler): async def on_turn(self, turn_context: TurnContext): @@ -55,26 +63,26 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "fileConsent/invoke": return await self.on_teams_file_consent( - turn_context, turn_context.activity.value + turn_context, FileConsentCardResponse(**turn_context.activity.value) ) if turn_context.activity.name == "actionableMessage/executeAction": await self.on_teams_o365_connector_card_action( - turn_context, turn_context.activity.value + turn_context, O365ConnectorCardActionQuery(**turn_context.activity.value) ) return self._create_invoke_response() if turn_context.activity.name == "composeExtension/queryLink": return self._create_invoke_response( await self.on_teams_app_based_link_query( - turn_context, turn_context.activity.value + turn_context, AppBasedLinkQuery(**turn_context.activity.value) ) ) if turn_context.activity.name == "composeExtension/query": return self._create_invoke_response( await self.on_teams_messaging_extension_query( - turn_context, turn_context.activity.value + turn_context, MessagingExtensionQuery(**turn_context.activity.value) ) ) @@ -88,21 +96,21 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "composeExtension/submitAction": return self._create_invoke_response( await self.on_teams_messaging_extension_submit_action_dispatch( - turn_context, turn_context.activity.value + turn_context, MessagingExtensionAction(**turn_context.activity.value) ) ) if turn_context.activity.name == "composeExtension/fetchTask": return self._create_invoke_response( await self.on_teams_messaging_extension_fetch_task( - turn_context, turn_context.activity.value + turn_context, MessagingExtensionAction(**turn_context.activity.value) ) ) if turn_context.activity.name == "composeExtension/querySettingUrl": return self._create_invoke_response( await self.on_teams_messaging_extension_configuration_query_settings_url( - turn_context, turn_context.activity.value + turn_context, MessagingExtensionQuery(**turn_context.activity.value) ) ) @@ -121,14 +129,14 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "task/fetch": return self._create_invoke_response( await self.on_teams_task_module_fetch( - turn_context, turn_context.activity.value + turn_context, TaskModuleRequest(**turn_context.activity.value) ) ) if turn_context.activity.name == "task/submit": return self._create_invoke_response( await self.on_teams_task_module_submit( - turn_context, turn_context.activity.value + turn_context, TaskModuleRequest(**turn_context.activity.value) ) ) @@ -143,7 +151,7 @@ async def on_teams_signin_verify_state(self, turn_context: TurnContext): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_file_consent( - self, turn_context: TurnContext, file_consent_card_response + self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse ): if file_consent_card_response.action == "accept": await self.on_teams_file_consent_accept_activity( @@ -163,39 +171,39 @@ async def on_teams_file_consent( ) async def on_teams_file_consent_accept_activity( # pylint: disable=unused-argument - self, turn_context: TurnContext, file_consent_card_response + self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_file_consent_decline_activity( # pylint: disable=unused-argument - self, turn_context: TurnContext, file_consent_card_response + self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_o365_connector_card_action( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query: O365ConnectorCardActionQuery ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_app_based_link_query( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query: AppBasedLinkQuery ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_query( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query: MessagingExtensionQuery ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_select_item( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_submit_action_dispatch( - self, turn_context: TurnContext, action + self, turn_context: TurnContext, action: MessagingExtensionAction ): - if not action: + if not action.bot_message_preview_action: return await self.on_teams_messaging_extension_submit_action_activity( turn_context, action ) @@ -226,17 +234,17 @@ async def on_teams_messaging_extension_bot_message_send_activity( # pylint: dis raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_submit_action_activity( # pylint: disable=unused-argument - self, turn_context: TurnContext, action + self, turn_context: TurnContext, action: MessagingExtensionAction ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_fetch_task( # pylint: disable=unused-argument - self, turn_context: TurnContext, task_module_request + self, turn_context: TurnContext, action: MessagingExtensionAction ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_configuration_query_settings_url( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query: MessagingExtensionQuery ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) @@ -251,19 +259,19 @@ async def on_teams_messaging_extension_card_button_clicked( # pylint: disable=u raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_task_module_fetch( # pylint: disable=unused-argument - self, turn_context: TurnContext, task_module_request + self, turn_context: TurnContext, task_module_request: TaskModuleRequest ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_task_module_submit( # pylint: disable=unused-argument - self, turn_context: TurnContext, task_module_request + self, turn_context: TurnContext, task_module_request: TaskModuleRequest ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_conversation_update_activity(self, turn_context: TurnContext): + if turn_context.activity.channel_id == Channels.ms_teams: channel_data = TeamsChannelData(**turn_context.activity.channel_data) - if turn_context.activity.members_added: return await self.on_teams_members_added_dispatch_activity( turn_context.activity.members_added, channel_data.team, turn_context @@ -279,7 +287,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): if channel_data: if channel_data.event_type == "channelCreated": return await self.on_teams_channel_created_activity( - channel_data.channel, channel_data.team, turn_context + ChannelInfo(**channel_data.channel), channel_data.team, turn_context ) if channel_data.event_type == "channelDeleted": return await self.on_teams_channel_deleted_activity( @@ -290,9 +298,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): channel_data.channel, channel_data.team, turn_context ) if channel_data.event_type == "teamRenamed": - return await self.on_teams_team_renamed_activity( - channel_data.team, turn_context - ) + return await self.on_teams_team_renamed_activity(channel_data.team, turn_context) return await super().on_conversation_update_activity(turn_context) return await super().on_conversation_update_activity(turn_context) @@ -300,7 +306,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): async def on_teams_channel_created_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): - return + return async def on_teams_team_renamed_activity( # pylint: disable=unused-argument self, team_info: TeamInfo, turn_context: TurnContext @@ -337,17 +343,20 @@ async def on_teams_members_added_dispatch_activity( # pylint: disable=unused-ar return await self.on_teams_members_added_activity(teams_members_added, team_info, turn_context) """ + team_accounts_added = [] for member in members_added: new_account_json = member.serialize() - del new_account_json["additional_properties"] + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] member = TeamsChannelAccount(**new_account_json) - return await self.on_teams_members_added_activity(members_added, turn_context) + team_accounts_added.append(member) + return await self.on_teams_members_added_activity(team_accounts_added, turn_context) async def on_teams_members_added_activity( self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext ): - teams_members_added = [ChannelAccount(member) for member in teams_members_added] - return super().on_members_added_activity(teams_members_added, turn_context) + teams_members_added = [ ChannelAccount(**member.serialize()) for member in teams_members_added ] + return await super().on_members_added_activity(teams_members_added, turn_context) async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused-argument self, @@ -358,7 +367,8 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- teams_members_removed = [] for member in members_removed: new_account_json = member.serialize() - del new_account_json["additional_properties"] + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] teams_members_removed.append(TeamsChannelAccount(**new_account_json)) return await self.on_teams_members_removed_activity( @@ -368,8 +378,8 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- async def on_teams_members_removed_activity( self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext ): - members_removed = [ChannelAccount(member) for member in teams_members_removed] - return super().on_members_removed_activity(members_removed, turn_context) + members_removed = [ChannelAccount(**member.serialize()) for member in teams_members_removed] + return await super().on_members_removed_activity(members_removed, turn_context) async def on_teams_channel_deleted_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext diff --git a/libraries/botbuilder-core/tests/__init__.py b/libraries/botbuilder-core/tests/__init__.py new file mode 100644 index 000000000..bc1cb1d65 --- /dev/null +++ b/libraries/botbuilder-core/tests/__init__.py @@ -0,0 +1,3 @@ +from .simple_adapter import SimpleAdapter + +__all__ = ["SimpleAdapter"] \ No newline at end of file diff --git a/libraries/botbuilder-core/tests/teams/__init__.py b/libraries/botbuilder-core/tests/teams/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 87b092e09..1d39fd823 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -3,6 +3,7 @@ import aiounittest from botbuilder.core import BotAdapter, TurnContext from botbuilder.core.teams import TeamsActivityHandler +from .. import SimpleAdapter from botbuilder.schema import ( Activity, ActivityTypes, @@ -11,44 +12,44 @@ MessageReaction, ResourceResponse, ) - +from botbuilder.schema.teams import ( + AppBasedLinkQuery, + ChannelInfo, + FileConsentCardResponse, + MessageActionsPayload, + MessagingExtensionAction, + MessagingExtensionQuery, + NotificationInfo, + O365ConnectorCardActionQuery, + TaskModuleRequest, + TaskModuleRequestContext, + TeamInfo, + TeamsChannelAccount, + TeamsChannelData, + TenantInfo, +) +from botframework.connector import Channels class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): self.record: List[str] = [] + async def on_conversation_update_activity(self, turn_context: TurnContext): + self.record.append("on_conversation_update_activity") + return await super().on_conversation_update_activity(turn_context) + + async def on_teams_members_added_activity(self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_added_activity") + return await super().on_teams_members_added_activity(teams_members_added, turn_context) + + async def on_teams_members_removed_activity(self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_removed_activity") + return await super().on_teams_members_removed_activity(teams_members_removed, turn_context) + async def on_message_activity(self, turn_context: TurnContext): self.record.append("on_message_activity") return await super().on_message_activity(turn_context) - async def on_members_added_activity( - self, members_added: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_added_activity") - return await super().on_members_added_activity(members_added, turn_context) - - async def on_members_removed_activity( - self, members_removed: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_removed_activity") - return await super().on_members_removed_activity(members_removed, turn_context) - - async def on_message_reaction_activity(self, turn_context: TurnContext): - self.record.append("on_message_reaction_activity") - return await super().on_message_reaction_activity(turn_context) - - async def on_reactions_added( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_added") - return await super().on_reactions_added(message_reactions, turn_context) - - async def on_reactions_removed( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_removed") - return await super().on_reactions_removed(message_reactions, turn_context) - async def on_token_response_event(self, turn_context: TurnContext): self.record.append("on_token_response_event") return await super().on_token_response_event(turn_context) @@ -60,7 +61,130 @@ async def on_event(self, turn_context: TurnContext): async def on_unrecognized_activity_type(self, turn_context: TurnContext): self.record.append("on_unrecognized_activity_type") return await super().on_unrecognized_activity_type(turn_context) + + async def on_teams_channel_created_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_created_activity") + return await super().on_teams_channel_created_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_renamed_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_renamed_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_deleted_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_deleted_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_team_renamed_activity(self, team_info: TeamInfo, turn_context: TurnContext): + self.record.append("on_teams_team_renamed_activity") + return await super().on_teams_team_renamed_activity(team_info, turn_context) + + async def on_invoke_activity(self, turn_context: TurnContext): + self.record.append("on_invoke_activity") + return await super().on_invoke_activity(turn_context) + + async def on_teams_signin_verify_state(self, turn_context: TurnContext): + self.record.append("on_teams_signin_verify_state") + return await super().on_teams_signin_verify_state(turn_context) + + async def on_teams_file_consent(self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse): + self.record.append("on_teams_file_consent") + return await super().on_teams_file_consent(turn_context, file_consent_card_response) + + async def on_teams_file_consent_accept_activity( + self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + ): + self.record.append("on_teams_file_consent_accept_activity") + return await super().on_teams_file_consent_accept_activity(turn_context, file_consent_card_response) + + async def on_teams_file_consent_decline_activity( + self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + ): + self.record.append("on_teams_file_consent_decline_activity") + return await super().on_teams_file_consent_decline_activity(turn_context, file_consent_card_response) + + async def on_teams_o365_connector_card_action( + self, turn_context: TurnContext, query: O365ConnectorCardActionQuery + ): + self.record.append("on_teams_o365_connector_card_action") + return await super().on_teams_o365_connector_card_action(turn_context, query) + + async def on_teams_app_based_link_query( + self, turn_context: TurnContext, query: AppBasedLinkQuery + ): + self.record.append("on_teams_app_based_link_query") + return await super().on_teams_app_based_link_query(turn_context, query) + + async def on_teams_messaging_extension_query( + self, turn_context: TurnContext, query: MessagingExtensionQuery + ): + self.record.append("on_teams_messaging_extension_query") + return await super().on_teams_messaging_extension_query(turn_context, query) + + async def on_teams_messaging_extension_submit_action_dispatch( + self, turn_context: TurnContext, action: MessagingExtensionAction + ): + self.record.append("on_teams_messaging_extension_submit_action_dispatch") + return await super().on_teams_messaging_extension_submit_action_dispatch(turn_context, action) + + async def on_teams_messaging_extension_submit_action_activity( + self, turn_context: TurnContext, action: MessagingExtensionAction + ): + self.record.append("on_teams_messaging_extension_submit_action_activity") + return await super().on_teams_messaging_extension_submit_action_activity(turn_context, action) + + async def on_teams_messaging_extension_bot_message_preview_edit_activity( + self, turn_context: TurnContext, action: MessagingExtensionAction + ): + self.record.append("on_teams_messaging_extension_bot_message_preview_edit_activity") + return await super().on_teams_messaging_extension_bot_message_preview_edit_activity(turn_context, action) + + async def on_teams_messaging_extension_bot_message_send_activity( + self, turn_context: TurnContext, action: MessagingExtensionAction + ): + self.record.append("on_teams_messaging_extension_bot_message_send_activity") + return await super().on_teams_messaging_extension_bot_message_send_activity(turn_context, action) + + async def on_teams_messaging_extension_fetch_task( + self, turn_context: TurnContext, action: MessagingExtensionAction + ): + self.record.append("on_teams_messaging_extension_fetch_task") + return await super().on_teams_messaging_extension_fetch_task(turn_context, action) + + async def on_teams_messaging_extension_configuration_query_settings_url( + self, turn_context: TurnContext, query: MessagingExtensionQuery + ): + self.record.append("on_teams_messaging_extension_configuration_query_settings_url") + return await super().on_teams_messaging_extension_configuration_query_settings_url(turn_context, query) + + async def on_teams_messaging_extension_configuration_setting( + self, turn_context: TurnContext, settings + ): + self.record.append("on_teams_messaging_extension_configuration_setting") + return await super().on_teams_messaging_extension_configuration_setting(turn_context, settings) + + async def on_teams_messaging_extension_card_button_clicked( + self, turn_context: TurnContext, card_data + ): + self.record.append("on_teams_messaging_extension_card_button_clicked") + return await super().on_teams_messaging_extension_card_button_clicked(turn_context, card_data) + + async def on_teams_task_module_fetch( + self, turn_context: TurnContext, task_module_request + ): + self.record.append("on_teams_task_module_fetch") + return await super().on_teams_task_module_fetch(turn_context, task_module_request) + async def on_teams_task_module_submit( # pylint: disable=unused-argument + self, turn_context: TurnContext, task_module_request: TaskModuleRequest + ): + self.record.append("on_teams_task_module_submit") + return await super().on_teams_task_module_submit(turn_context, task_module_request) class NotImplementedAdapter(BotAdapter): async def delete_activity( @@ -76,18 +200,46 @@ async def send_activities( async def update_activity(self, context: TurnContext, activity: Activity): raise NotImplementedError() - class TestTeamsActivityHandler(aiounittest.AsyncTestCase): - async def test_message_reaction(self): - # Note the code supports multiple adds and removes in the same activity though - # a channel may decide to send separate activities for each. For example, Teams - # sends separate activities each with a single add and a single remove. + async def test_on_teams_channel_created_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelCreated", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) - # Arrange + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_created_activity" + + async def test_on_teams_channel_renamed_activity(self): + #arrange activity = Activity( - type=ActivityTypes.message_reaction, - reactions_added=[MessageReaction(type="sad")], + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelRenamed", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams ) + turn_context = TurnContext(NotImplementedAdapter(), activity) # Act @@ -96,5 +248,468 @@ async def test_message_reaction(self): # Assert assert len(bot.record) == 2 - assert bot.record[0] == "on_message_reaction_activity" - assert bot.record[1] == "on_reactions_added" + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_renamed_activity" + + async def test_on_teams_channel_deleted_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelDeleted", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_deleted_activity" + + async def test_on_teams_team_renamed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamRenamed", + "team": { + "id": "team_id_1", + "name" : "new_team_name" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_team_renamed_activity" + + async def test_on_teams_members_added_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberAdded" + }, + members_added = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_added_activity" + + async def test_on_teams_members_removed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberRemoved" + }, + members_removed = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_removed_activity" + + async def test_on_signin_verify_state(self): + #arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "signin/verifyState" + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_signin_verify_state" + + async def test_on_file_consent_accept_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "fileConsent/invoke", + value = {"action" : "accept"} + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_file_consent" + assert bot.record[2] == "on_teams_file_consent_accept_activity" + + async def test_on_file_consent_decline_activity(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "fileConsent/invoke", + value = {"action" : "decline"} + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_file_consent" + assert bot.record[2] == "on_teams_file_consent_decline_activity" + + async def test_on_file_consent_bad_action_activity(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "fileConsent/invoke", + value = {"action" : "bad_action"} + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_file_consent" + + async def test_on_teams_o365_connector_card_action(self): + #arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "actionableMessage/executeAction", + value = { + "body": "body_here", + "actionId": "action_id_here" + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_o365_connector_card_action" + + async def test_on_app_based_link_query(self): + #arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/query", + value = { + "url": "http://www.test.com" + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_query" + + async def test_on_teams_messaging_extension_bot_message_preview_edit_activity(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/submitAction", + value = { + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "edit", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" + assert bot.record[2] == "on_teams_messaging_extension_bot_message_preview_edit_activity" + + async def test_on_teams_messaging_extension_bot_message_send_activity(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/submitAction", + value = { + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "send", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" + assert bot.record[2] == "on_teams_messaging_extension_bot_message_send_activity" + + async def test_on_teams_messaging_extension_bot_message_send_activity_with_none(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/submitAction", + value = { + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": None, + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" + assert bot.record[2] == "on_teams_messaging_extension_submit_action_activity" + + async def test_on_teams_messaging_extension_bot_message_send_activity_with_empty_string(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/submitAction", + value = { + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 3 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" + assert bot.record[2] == "on_teams_messaging_extension_submit_action_activity" + + async def test_on_teams_messaging_extension_fetch_task(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/fetchTask", + value = { + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "message_action", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_fetch_task" + + async def test_on_teams_messaging_extension_configuration_query_settings_url(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/querySettingUrl", + value = { + "comamndId": "test_command", + "parameters": [], + "messagingExtensionQueryOptions": {"skip": 1, "count": 1}, + "state": "state_string", + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_configuration_query_settings_url" + + async def test_on_teams_messaging_extension_configuration_setting(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/setting", + value = { + "key": "value" + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_configuration_setting" + + async def test_on_teams_messaging_extension_card_button_clicked(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "composeExtension/onCardButtonClicked", + value = { + "key": "value" + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_messaging_extension_card_button_clicked" + + async def test_on_teams_task_module_fetch(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "task/fetch", + value = { + "data": {"key": "value"}, + "context": TaskModuleRequestContext().serialize() + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_task_module_fetch" + + async def test_on_teams_task_module_submit(self): + # Arrange + activity = Activity( + type = ActivityTypes.invoke, + name = "task/submit", + value = { + "data": {"key": "value"}, + "context": TaskModuleRequestContext().serialize() + } + ) + + turn_context = TurnContext(SimpleAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_invoke_activity" + assert bot.record[1] == "on_teams_task_module_submit" \ No newline at end of file diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models.py b/libraries/botbuilder-schema/botbuilder/schema/_models.py index 736ddcf81..9574df14a 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models.py @@ -611,7 +611,7 @@ def __init__(self, **kwargs): super(ChannelAccount, self).__init__(**kwargs) self.id = kwargs.get("id", None) self.name = kwargs.get("name", None) - self.aad_object_id = kwargs.get("aad_object_id", None) + self.aad_object_id = kwargs.get("aadObjectId", None) self.role = kwargs.get("role", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index 58caa1567..b6b9f1aac 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -730,14 +730,14 @@ def __init__( *, id: str = None, name: str = None, - aad_object_id: str = None, + aadObjectId: str = None, role=None, **kwargs ) -> None: super(ChannelAccount, self).__init__(**kwargs) self.id = id self.name = name - self.aad_object_id = aad_object_id + self.aad_object_id = aadObjectId self.role = role diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py index 5e41c6fd4..f348245af 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py @@ -559,7 +559,7 @@ def __init__(self, **kwargs): super(MessagingExtensionAction, self).__init__(**kwargs) self.command_id = kwargs.get("command_id", None) self.command_context = kwargs.get("command_context", None) - self.bot_message_preview_action = kwargs.get("bot_message_preview_action", None) + self.bot_message_preview_action = kwargs.get("botMessagePreviewAction", None) self.bot_activity_preview = kwargs.get("bot_activity_preview", None) self.message_payload = kwargs.get("message_payload", None) @@ -910,7 +910,8 @@ class O365ConnectorCardActionQuery(Model): def __init__(self, **kwargs): super(O365ConnectorCardActionQuery, self).__init__(**kwargs) self.body = kwargs.get("body", None) - self.action_id = kwargs.get("action_id", None) + # This is how it comes in from Teams + self.action_id = kwargs.get("actionId", None) class O365ConnectorCardDateInput(O365ConnectorCardInputBase): @@ -1535,7 +1536,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__(self, **kwargs): @@ -1543,7 +1544,7 @@ def __init__(self, **kwargs): self.given_name = kwargs.get("given_name", None) self.surname = kwargs.get("surname", None) self.email = kwargs.get("email", None) - self.user_principal_name = kwargs.get("user_principal_name", None) + self.userPrincipalName = kwargs.get("userPrincipalName", None) class TeamsChannelData(Model): @@ -1573,7 +1574,8 @@ class TeamsChannelData(Model): def __init__(self, **kwargs): super(TeamsChannelData, self).__init__(**kwargs) self.channel = kwargs.get("channel", None) - self.event_type = kwargs.get("event_type", None) + # doing camel case here since that's how the data comes in + self.event_type = kwargs.get("eventType", None) self.team = kwargs.get("team", None) self.notification = kwargs.get("notification", None) self.tenant = kwargs.get("tenant", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 80249f277..612f59cde 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -670,7 +670,7 @@ def __init__( context=None, command_id: str = None, command_context=None, - bot_message_preview_action=None, + botMessagePreviewAction=None, bot_activity_preview=None, message_payload=None, **kwargs @@ -680,7 +680,7 @@ def __init__( ) self.command_id = command_id self.command_context = command_context - self.bot_message_preview_action = bot_message_preview_action + self.bot_message_preview_action = botMessagePreviewAction self.bot_activity_preview = bot_activity_preview self.message_payload = message_payload @@ -1129,10 +1129,11 @@ class O365ConnectorCardActionQuery(Model): "action_id": {"key": "actionId", "type": "str"}, } - def __init__(self, *, body: str = None, action_id: str = None, **kwargs) -> None: + def __init__(self, *, body: str = None, actionId: str = None, **kwargs) -> None: super(O365ConnectorCardActionQuery, self).__init__(**kwargs) self.body = body - self.action_id = action_id + # This is how it comes in from Teams + self.action_id = actionId class O365ConnectorCardDateInput(O365ConnectorCardInputBase): @@ -1796,7 +1797,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__( @@ -1807,14 +1808,15 @@ def __init__( given_name: str = None, surname: str = None, email: str = None, - user_principal_name: str = None, + userPrincipalName: str = None, **kwargs ) -> None: super(TeamsChannelAccount, self).__init__(id=id, name=name, **kwargs) self.given_name = given_name self.surname = surname self.email = email - self.user_principal_name = user_principal_name + # changing to camel case due to how data comes in off the wire + self.userPrincipalName = userPrincipalName class TeamsChannelData(Model): @@ -1845,7 +1847,7 @@ def __init__( self, *, channel=None, - event_type: str = None, + eventType: str = None, team=None, notification=None, tenant=None, @@ -1853,7 +1855,8 @@ def __init__( ) -> None: super(TeamsChannelData, self).__init__(**kwargs) self.channel = channel - self.event_type = event_type + # doing camel case here since that's how the data comes in + self.event_type = eventType self.team = team self.notification = notification self.tenant = tenant From fa499557de19105345b76a35b5f30b63ce938b95 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 17:15:26 -0800 Subject: [PATCH 3/8] resolving merge conflict --- .../core/teams/teams_activity_handler.py | 43 ++-- .../teams/test_teams_activity_handler.py | 217 ++++++++++++++---- .../botbuilder/schema/_models.py | 2 +- .../botbuilder/schema/_models_py3.py | 6 +- .../botbuilder/schema/teams/_models.py | 7 +- .../botbuilder/schema/teams/_models_py3.py | 14 +- 6 files changed, 221 insertions(+), 68 deletions(-) diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py index 7ff3cf4ec..74468ac78 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -12,7 +12,8 @@ TeamsChannelAccount, ) from botframework.connector import Channels - +import json +from typing import List class TeamsActivityHandler(ActivityHandler): async def on_turn(self, turn_context: TurnContext): @@ -261,9 +262,9 @@ async def on_teams_task_module_submit( # pylint: disable=unused-argument raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_conversation_update_activity(self, turn_context: TurnContext): + if turn_context.activity.channel_id == Channels.ms_teams: channel_data = TeamsChannelData(**turn_context.activity.channel_data) - if turn_context.activity.members_added: return await self.on_teams_members_added_dispatch_activity( turn_context.activity.members_added, channel_data.team, turn_context @@ -277,22 +278,20 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): ) if channel_data: - if channel_data.event_type == "channelCreated": + if channel_data.eventType == "channelCreated": return await self.on_teams_channel_created_activity( - channel_data.channel, channel_data.team, turn_context + ChannelInfo(**channel_data.channel), channel_data.team, turn_context ) - if channel_data.event_type == "channelDeleted": + if channel_data.eventType == "channelDeleted": return await self.on_teams_channel_deleted_activity( channel_data.channel, channel_data.team, turn_context ) - if channel_data.event_type == "channelRenamed": + if channel_data.eventType == "channelRenamed": return await self.on_teams_channel_renamed_activity( channel_data.channel, channel_data.team, turn_context ) - if channel_data.event_type == "teamRenamed": - return await self.on_teams_team_renamed_activity( - channel_data.team, turn_context - ) + if channel_data.eventType == "teamRenamed": + return await self.on_teams_team_renamed_activity(channel_data.team, turn_context) return await super().on_conversation_update_activity(turn_context) return await super().on_conversation_update_activity(turn_context) @@ -300,7 +299,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): async def on_teams_channel_created_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): - return + return async def on_teams_team_renamed_activity( # pylint: disable=unused-argument self, team_info: TeamInfo, turn_context: TurnContext @@ -337,17 +336,24 @@ async def on_teams_members_added_dispatch_activity( # pylint: disable=unused-ar return await self.on_teams_members_added_activity(teams_members_added, team_info, turn_context) """ + team_accounts_added = [] for member in members_added: new_account_json = member.serialize() +<<<<<<< HEAD del new_account_json["additional_properties"] +======= + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] +>>>>>>> e682f38... saving unit tests so far member = TeamsChannelAccount(**new_account_json) - return await self.on_teams_members_added_activity(members_added, turn_context) + team_accounts_added.append(member) + return await self.on_teams_members_added_activity(team_accounts_added, turn_context) async def on_teams_members_added_activity( self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext ): - teams_members_added = [ChannelAccount(member) for member in teams_members_added] - return super().on_members_added_activity(teams_members_added, turn_context) + teams_members_added = [ ChannelAccount(**member.serialize()) for member in teams_members_added ] + return await super().on_members_added_activity(teams_members_added, turn_context) async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused-argument self, @@ -358,7 +364,12 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- teams_members_removed = [] for member in members_removed: new_account_json = member.serialize() +<<<<<<< HEAD del new_account_json["additional_properties"] +======= + if "additional_properties" in new_account_json: + del new_account_json["additional_properties"] +>>>>>>> e682f38... saving unit tests so far teams_members_removed.append(TeamsChannelAccount(**new_account_json)) return await self.on_teams_members_removed_activity( @@ -368,8 +379,8 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- async def on_teams_members_removed_activity( self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext ): - members_removed = [ChannelAccount(member) for member in teams_members_removed] - return super().on_members_removed_activity(members_removed, turn_context) + members_removed = [ChannelAccount(**member.serialize()) for member in teams_members_removed] + return await super().on_members_removed_activity(members_removed, turn_context) async def on_teams_channel_deleted_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 87b092e09..2b04c1f09 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -11,44 +11,36 @@ MessageReaction, ResourceResponse, ) - +from botbuilder.schema.teams import ( + ChannelInfo, + NotificationInfo, + TeamInfo, + TeamsChannelAccount, + TeamsChannelData, + TenantInfo, +) +from botframework.connector import Channels class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): self.record: List[str] = [] + async def on_conversation_update_activity(self, turn_context: TurnContext): + self.record.append("on_conversation_update_activity") + return await super().on_conversation_update_activity(turn_context) + + async def on_teams_members_added_activity(self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_added_activity") + return await super().on_teams_members_added_activity(teams_members_added, turn_context) + + async def on_teams_members_removed_activity(self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext): + self.record.append("on_teams_members_removed_activity") + return await super().on_teams_members_removed_activity(teams_members_removed, turn_context) + async def on_message_activity(self, turn_context: TurnContext): self.record.append("on_message_activity") return await super().on_message_activity(turn_context) - async def on_members_added_activity( - self, members_added: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_added_activity") - return await super().on_members_added_activity(members_added, turn_context) - - async def on_members_removed_activity( - self, members_removed: ChannelAccount, turn_context: TurnContext - ): - self.record.append("on_members_removed_activity") - return await super().on_members_removed_activity(members_removed, turn_context) - - async def on_message_reaction_activity(self, turn_context: TurnContext): - self.record.append("on_message_reaction_activity") - return await super().on_message_reaction_activity(turn_context) - - async def on_reactions_added( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_added") - return await super().on_reactions_added(message_reactions, turn_context) - - async def on_reactions_removed( - self, message_reactions: List[MessageReaction], turn_context: TurnContext - ): - self.record.append("on_reactions_removed") - return await super().on_reactions_removed(message_reactions, turn_context) - async def on_token_response_event(self, turn_context: TurnContext): self.record.append("on_token_response_event") return await super().on_token_response_event(turn_context) @@ -60,7 +52,32 @@ async def on_event(self, turn_context: TurnContext): async def on_unrecognized_activity_type(self, turn_context: TurnContext): self.record.append("on_unrecognized_activity_type") return await super().on_unrecognized_activity_type(turn_context) + + async def on_teams_channel_created_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_created_activity") + return await super().on_teams_channel_created_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_renamed_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_renamed_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_channel_deleted_activity( + self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext + ): + self.record.append("on_teams_channel_deleted_activity") + return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) + + async def on_teams_team_renamed_activity(self, team_info: TeamInfo, turn_context: TurnContext): + self.record.append("on_teams_team_renamed_activity") + return await super().on_teams_team_renamed_activity(team_info, turn_context) + async def on_invoke_activity(self, turn_context: TurnContext): + self.record.append("on_invoke_activity") + return await super().on_invoke_activity(turn_context) class NotImplementedAdapter(BotAdapter): async def delete_activity( @@ -76,18 +93,140 @@ async def send_activities( async def update_activity(self, context: TurnContext, activity: Activity): raise NotImplementedError() - class TestTeamsActivityHandler(aiounittest.AsyncTestCase): - async def test_message_reaction(self): - # Note the code supports multiple adds and removes in the same activity though - # a channel may decide to send separate activities for each. For example, Teams - # sends separate activities each with a single add and a single remove. + async def test_on_teams_channel_created_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelCreated", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_created_activity" + + async def test_on_teams_channel_renamed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelRenamed", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) - # Arrange + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_renamed_activity" + + async def test_on_teams_channel_deleted_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "channelDeleted", + "channel": { + "id": "asdfqwerty", + "name" : "new_channel" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_channel_deleted_activity" + + async def test_on_teams_team_renamed_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamRenamed", + "team": { + "id": "team_id_1", + "name" : "new_team_name" + } + }, + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_team_renamed_activity" + + async def test_on_teams_members_added_activity(self): + #arrange + activity = Activity( + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberAdded" + }, + members_added = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams + ) + + turn_context = TurnContext(NotImplementedAdapter(), activity) + + # Act + bot = TestingTeamsActivityHandler() + await bot.on_turn(turn_context) + + # Assert + assert len(bot.record) == 2 + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_added_activity" + + async def test_on_teams_members_removed_activity(self): + #arrange activity = Activity( - type=ActivityTypes.message_reaction, - reactions_added=[MessageReaction(type="sad")], + type = ActivityTypes.conversation_update, + channel_data = { + "eventType": "teamMemberRemoved" + }, + members_removed = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], + channel_id = Channels.ms_teams ) + turn_context = TurnContext(NotImplementedAdapter(), activity) # Act @@ -96,5 +235,5 @@ async def test_message_reaction(self): # Assert assert len(bot.record) == 2 - assert bot.record[0] == "on_message_reaction_activity" - assert bot.record[1] == "on_reactions_added" + assert bot.record[0] == "on_conversation_update_activity" + assert bot.record[1] == "on_teams_members_removed_activity" \ No newline at end of file diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models.py b/libraries/botbuilder-schema/botbuilder/schema/_models.py index 736ddcf81..dc40b3fee 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models.py @@ -611,7 +611,7 @@ def __init__(self, **kwargs): super(ChannelAccount, self).__init__(**kwargs) self.id = kwargs.get("id", None) self.name = kwargs.get("name", None) - self.aad_object_id = kwargs.get("aad_object_id", None) + self.aadObjectId = kwargs.get("aadObjectId", None) self.role = kwargs.get("role", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index 58caa1567..c6cd5fdba 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -721,7 +721,7 @@ class ChannelAccount(Model): _attribute_map = { "id": {"key": "id", "type": "str"}, "name": {"key": "name", "type": "str"}, - "aad_object_id": {"key": "aadObjectId", "type": "str"}, + "aadObjectId": {"key": "aadObjectId", "type": "str"}, "role": {"key": "role", "type": "str"}, } @@ -730,14 +730,14 @@ def __init__( *, id: str = None, name: str = None, - aad_object_id: str = None, + aadObjectId: str = None, role=None, **kwargs ) -> None: super(ChannelAccount, self).__init__(**kwargs) self.id = id self.name = name - self.aad_object_id = aad_object_id + self.aadObjectId = aadObjectId self.role = role diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py index 5e41c6fd4..fe0e5d741 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py @@ -1535,7 +1535,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__(self, **kwargs): @@ -1543,7 +1543,7 @@ def __init__(self, **kwargs): self.given_name = kwargs.get("given_name", None) self.surname = kwargs.get("surname", None) self.email = kwargs.get("email", None) - self.user_principal_name = kwargs.get("user_principal_name", None) + self.userPrincipalName = kwargs.get("userPrincipalName", None) class TeamsChannelData(Model): @@ -1573,7 +1573,8 @@ class TeamsChannelData(Model): def __init__(self, **kwargs): super(TeamsChannelData, self).__init__(**kwargs) self.channel = kwargs.get("channel", None) - self.event_type = kwargs.get("event_type", None) + # doing camel case here since that's how the data comes in + self.eventType = kwargs.get("eventType", None) self.team = kwargs.get("team", None) self.notification = kwargs.get("notification", None) self.tenant = kwargs.get("tenant", None) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 80249f277..3cd336941 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -1796,7 +1796,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "user_principal_name": {"key": "userPrincipalName", "type": "str"}, + "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, } def __init__( @@ -1807,14 +1807,15 @@ def __init__( given_name: str = None, surname: str = None, email: str = None, - user_principal_name: str = None, + userPrincipalName: str = None, **kwargs ) -> None: super(TeamsChannelAccount, self).__init__(id=id, name=name, **kwargs) self.given_name = given_name self.surname = surname self.email = email - self.user_principal_name = user_principal_name + # changing to camel case due to how data comes in off the wire + self.userPrincipalName = userPrincipalName class TeamsChannelData(Model): @@ -1835,7 +1836,7 @@ class TeamsChannelData(Model): _attribute_map = { "channel": {"key": "channel", "type": "ChannelInfo"}, - "event_type": {"key": "eventType", "type": "str"}, + "eventType": {"key": "eventType", "type": "str"}, "team": {"key": "team", "type": "TeamInfo"}, "notification": {"key": "notification", "type": "NotificationInfo"}, "tenant": {"key": "tenant", "type": "TenantInfo"}, @@ -1845,7 +1846,7 @@ def __init__( self, *, channel=None, - event_type: str = None, + eventType: str = None, team=None, notification=None, tenant=None, @@ -1853,7 +1854,8 @@ def __init__( ) -> None: super(TeamsChannelData, self).__init__(**kwargs) self.channel = channel - self.event_type = event_type + # doing camel case here since that's how the data comes in + self.eventType = eventType self.team = team self.notification = notification self.tenant = tenant From 5fb0b92be971fde1136dbc97b884dbc660225d59 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 21:24:39 -0800 Subject: [PATCH 4/8] adding init files for adapter import --- libraries/botbuilder-core/tests/__init__.py | 3 +++ libraries/botbuilder-core/tests/teams/__init__.py | 0 .../tests/teams/test_teams_activity_handler.py | 1 + .../botbuilder-schema/botbuilder/schema/_models_py3.py | 6 +++--- .../botbuilder/schema/teams/_models_py3.py | 6 +++--- 5 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 libraries/botbuilder-core/tests/__init__.py create mode 100644 libraries/botbuilder-core/tests/teams/__init__.py diff --git a/libraries/botbuilder-core/tests/__init__.py b/libraries/botbuilder-core/tests/__init__.py new file mode 100644 index 000000000..bc1cb1d65 --- /dev/null +++ b/libraries/botbuilder-core/tests/__init__.py @@ -0,0 +1,3 @@ +from .simple_adapter import SimpleAdapter + +__all__ = ["SimpleAdapter"] \ No newline at end of file diff --git a/libraries/botbuilder-core/tests/teams/__init__.py b/libraries/botbuilder-core/tests/teams/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 2b04c1f09..9184ee789 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -20,6 +20,7 @@ TenantInfo, ) from botframework.connector import Channels +from .. import SimpleAdapter class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index c6cd5fdba..58caa1567 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -721,7 +721,7 @@ class ChannelAccount(Model): _attribute_map = { "id": {"key": "id", "type": "str"}, "name": {"key": "name", "type": "str"}, - "aadObjectId": {"key": "aadObjectId", "type": "str"}, + "aad_object_id": {"key": "aadObjectId", "type": "str"}, "role": {"key": "role", "type": "str"}, } @@ -730,14 +730,14 @@ def __init__( *, id: str = None, name: str = None, - aadObjectId: str = None, + aad_object_id: str = None, role=None, **kwargs ) -> None: super(ChannelAccount, self).__init__(**kwargs) self.id = id self.name = name - self.aadObjectId = aadObjectId + self.aad_object_id = aad_object_id self.role = role diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 3cd336941..e9547f62a 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -1796,7 +1796,7 @@ class TeamsChannelAccount(ChannelAccount): "given_name": {"key": "givenName", "type": "str"}, "surname": {"key": "surname", "type": "str"}, "email": {"key": "email", "type": "str"}, - "userPrincipalName": {"key": "userPrincipalName", "type": "str"}, + "user_principal_name": {"key": "userPrincipalName", "type": "str"}, } def __init__( @@ -1807,7 +1807,7 @@ def __init__( given_name: str = None, surname: str = None, email: str = None, - userPrincipalName: str = None, + user_principal_name: str = None, **kwargs ) -> None: super(TeamsChannelAccount, self).__init__(id=id, name=name, **kwargs) @@ -1815,7 +1815,7 @@ def __init__( self.surname = surname self.email = email # changing to camel case due to how data comes in off the wire - self.userPrincipalName = userPrincipalName + self.user_principal_name = user_principal_name class TeamsChannelData(Model): From 9ed8110c6376f559d2cfefbd8580a20a7317c1a9 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 21:51:37 -0800 Subject: [PATCH 5/8] cleaning up activity handler and models --- .../botbuilder/core/teams/teams_activity_handler.py | 6 +++--- .../botbuilder-schema/botbuilder/schema/_models_py3.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py index d6fe66199..8e647b76f 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -285,15 +285,15 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): ) if channel_data: - if channel_data.eventType == "channelCreated": + if channel_data.event_type == "channelCreated": return await self.on_teams_channel_created_activity( ChannelInfo(**channel_data.channel), channel_data.team, turn_context ) - if channel_data.eventType == "channelDeleted": + if channel_data.event_type == "channelDeleted": return await self.on_teams_channel_deleted_activity( channel_data.channel, channel_data.team, turn_context ) - if channel_data.eventType == "channelRenamed": + if channel_data.event_type == "channelRenamed": return await self.on_teams_channel_renamed_activity( channel_data.channel, channel_data.team, turn_context ) diff --git a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py index b6b9f1aac..58caa1567 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/_models_py3.py @@ -730,14 +730,14 @@ def __init__( *, id: str = None, name: str = None, - aadObjectId: str = None, + aad_object_id: str = None, role=None, **kwargs ) -> None: super(ChannelAccount, self).__init__(**kwargs) self.id = id self.name = name - self.aad_object_id = aadObjectId + self.aad_object_id = aad_object_id self.role = role From e29840ed468cdcd07c030f75a98bea469b1dcc37 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Tue, 3 Dec 2019 22:39:54 -0800 Subject: [PATCH 6/8] fixing linting and black --- .../core/teams/teams_activity_handler.py | 63 +- libraries/botbuilder-core/tests/__init__.py | 2 +- .../teams/test_teams_activity_handler.py | 538 ++++++++++-------- .../botbuilder/schema/teams/_models.py | 2 +- .../botbuilder/schema/teams/_models_py3.py | 2 +- 5 files changed, 338 insertions(+), 269 deletions(-) diff --git a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py index 8e647b76f..6ab5f3830 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -12,15 +12,13 @@ FileConsentCardResponse, TeamsChannelData, TeamsChannelAccount, - MessageActionsPayload, MessagingExtensionAction, MessagingExtensionQuery, O365ConnectorCardActionQuery, - TaskModuleRequest + TaskModuleRequest, ) from botframework.connector import Channels -import json -from typing import List + class TeamsActivityHandler(ActivityHandler): async def on_turn(self, turn_context: TurnContext): @@ -68,7 +66,8 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "actionableMessage/executeAction": await self.on_teams_o365_connector_card_action( - turn_context, O365ConnectorCardActionQuery(**turn_context.activity.value) + turn_context, + O365ConnectorCardActionQuery(**turn_context.activity.value), ) return self._create_invoke_response() @@ -82,7 +81,8 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "composeExtension/query": return self._create_invoke_response( await self.on_teams_messaging_extension_query( - turn_context, MessagingExtensionQuery(**turn_context.activity.value) + turn_context, + MessagingExtensionQuery(**turn_context.activity.value), ) ) @@ -96,21 +96,24 @@ async def on_invoke_activity(self, turn_context: TurnContext): if turn_context.activity.name == "composeExtension/submitAction": return self._create_invoke_response( await self.on_teams_messaging_extension_submit_action_dispatch( - turn_context, MessagingExtensionAction(**turn_context.activity.value) + turn_context, + MessagingExtensionAction(**turn_context.activity.value), ) ) if turn_context.activity.name == "composeExtension/fetchTask": return self._create_invoke_response( await self.on_teams_messaging_extension_fetch_task( - turn_context, MessagingExtensionAction(**turn_context.activity.value) + turn_context, + MessagingExtensionAction(**turn_context.activity.value), ) ) if turn_context.activity.name == "composeExtension/querySettingUrl": return self._create_invoke_response( await self.on_teams_messaging_extension_configuration_query_settings_url( - turn_context, MessagingExtensionQuery(**turn_context.activity.value) + turn_context, + MessagingExtensionQuery(**turn_context.activity.value), ) ) @@ -151,7 +154,9 @@ async def on_teams_signin_verify_state(self, turn_context: TurnContext): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_file_consent( - self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, ): if file_consent_card_response.action == "accept": await self.on_teams_file_consent_accept_activity( @@ -171,12 +176,16 @@ async def on_teams_file_consent( ) async def on_teams_file_consent_accept_activity( # pylint: disable=unused-argument - self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_file_consent_decline_activity( # pylint: disable=unused-argument - self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) @@ -196,7 +205,7 @@ async def on_teams_messaging_extension_query( # pylint: disable=unused-argument raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_teams_messaging_extension_select_item( # pylint: disable=unused-argument - self, turn_context: TurnContext, query + self, turn_context: TurnContext, query ): raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) @@ -269,7 +278,7 @@ async def on_teams_task_module_submit( # pylint: disable=unused-argument raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) async def on_conversation_update_activity(self, turn_context: TurnContext): - + if turn_context.activity.channel_id == Channels.ms_teams: channel_data = TeamsChannelData(**turn_context.activity.channel_data) if turn_context.activity.members_added: @@ -287,7 +296,9 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): if channel_data: if channel_data.event_type == "channelCreated": return await self.on_teams_channel_created_activity( - ChannelInfo(**channel_data.channel), channel_data.team, turn_context + ChannelInfo(**channel_data.channel), + channel_data.team, + turn_context, ) if channel_data.event_type == "channelDeleted": return await self.on_teams_channel_deleted_activity( @@ -298,7 +309,9 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): channel_data.channel, channel_data.team, turn_context ) if channel_data.event_type == "teamRenamed": - return await self.on_teams_team_renamed_activity(channel_data.team, turn_context) + return await self.on_teams_team_renamed_activity( + channel_data.team, turn_context + ) return await super().on_conversation_update_activity(turn_context) return await super().on_conversation_update_activity(turn_context) @@ -306,7 +319,7 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): async def on_teams_channel_created_activity( # pylint: disable=unused-argument self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): - return + return async def on_teams_team_renamed_activity( # pylint: disable=unused-argument self, team_info: TeamInfo, turn_context: TurnContext @@ -350,13 +363,19 @@ async def on_teams_members_added_dispatch_activity( # pylint: disable=unused-ar del new_account_json["additional_properties"] member = TeamsChannelAccount(**new_account_json) team_accounts_added.append(member) - return await self.on_teams_members_added_activity(team_accounts_added, turn_context) + return await self.on_teams_members_added_activity( + team_accounts_added, turn_context + ) async def on_teams_members_added_activity( self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext ): - teams_members_added = [ ChannelAccount(**member.serialize()) for member in teams_members_added ] - return await super().on_members_added_activity(teams_members_added, turn_context) + teams_members_added = [ + ChannelAccount(**member.serialize()) for member in teams_members_added + ] + return await super().on_members_added_activity( + teams_members_added, turn_context + ) async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused-argument self, @@ -378,7 +397,9 @@ async def on_teams_members_removed_dispatch_activity( # pylint: disable=unused- async def on_teams_members_removed_activity( self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext ): - members_removed = [ChannelAccount(**member.serialize()) for member in teams_members_removed] + members_removed = [ + ChannelAccount(**member.serialize()) for member in teams_members_removed + ] return await super().on_members_removed_activity(members_removed, turn_context) async def on_teams_channel_deleted_activity( # pylint: disable=unused-argument diff --git a/libraries/botbuilder-core/tests/__init__.py b/libraries/botbuilder-core/tests/__init__.py index bc1cb1d65..6fff60cf5 100644 --- a/libraries/botbuilder-core/tests/__init__.py +++ b/libraries/botbuilder-core/tests/__init__.py @@ -1,3 +1,3 @@ from .simple_adapter import SimpleAdapter -__all__ = ["SimpleAdapter"] \ No newline at end of file +__all__ = ["SimpleAdapter"] diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 2b760fd15..06152f21b 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -3,13 +3,11 @@ import aiounittest from botbuilder.core import BotAdapter, TurnContext from botbuilder.core.teams import TeamsActivityHandler -from .. import SimpleAdapter from botbuilder.schema import ( Activity, ActivityTypes, ChannelAccount, ConversationReference, - MessageReaction, ResourceResponse, ) from botbuilder.schema.teams import ( @@ -19,16 +17,14 @@ MessageActionsPayload, MessagingExtensionAction, MessagingExtensionQuery, - NotificationInfo, O365ConnectorCardActionQuery, TaskModuleRequest, TaskModuleRequestContext, TeamInfo, TeamsChannelAccount, - TeamsChannelData, - TenantInfo, ) from botframework.connector import Channels +from .. import SimpleAdapter class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): @@ -38,13 +34,21 @@ async def on_conversation_update_activity(self, turn_context: TurnContext): self.record.append("on_conversation_update_activity") return await super().on_conversation_update_activity(turn_context) - async def on_teams_members_added_activity(self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext): + async def on_teams_members_added_activity( + self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext + ): self.record.append("on_teams_members_added_activity") - return await super().on_teams_members_added_activity(teams_members_added, turn_context) - - async def on_teams_members_removed_activity(self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext): + return await super().on_teams_members_added_activity( + teams_members_added, turn_context + ) + + async def on_teams_members_removed_activity( + self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext + ): self.record.append("on_teams_members_removed_activity") - return await super().on_teams_members_removed_activity(teams_members_removed, turn_context) + return await super().on_teams_members_removed_activity( + teams_members_removed, turn_context + ) async def on_message_activity(self, turn_context: TurnContext): self.record.append("on_message_activity") @@ -61,65 +65,87 @@ async def on_event(self, turn_context: TurnContext): async def on_unrecognized_activity_type(self, turn_context: TurnContext): self.record.append("on_unrecognized_activity_type") return await super().on_unrecognized_activity_type(turn_context) - + async def on_teams_channel_created_activity( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): self.record.append("on_teams_channel_created_activity") - return await super().on_teams_channel_created_activity(channel_info, team_info, turn_context) - + return await super().on_teams_channel_created_activity( + channel_info, team_info, turn_context + ) + async def on_teams_channel_renamed_activity( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): self.record.append("on_teams_channel_renamed_activity") - return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) - + return await super().on_teams_channel_renamed_activity( + channel_info, team_info, turn_context + ) + async def on_teams_channel_deleted_activity( self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext ): self.record.append("on_teams_channel_deleted_activity") - return await super().on_teams_channel_renamed_activity(channel_info, team_info, turn_context) - - async def on_teams_team_renamed_activity(self, team_info: TeamInfo, turn_context: TurnContext): + return await super().on_teams_channel_renamed_activity( + channel_info, team_info, turn_context + ) + + async def on_teams_team_renamed_activity( + self, team_info: TeamInfo, turn_context: TurnContext + ): self.record.append("on_teams_team_renamed_activity") return await super().on_teams_team_renamed_activity(team_info, turn_context) async def on_invoke_activity(self, turn_context: TurnContext): self.record.append("on_invoke_activity") return await super().on_invoke_activity(turn_context) - + async def on_teams_signin_verify_state(self, turn_context: TurnContext): self.record.append("on_teams_signin_verify_state") return await super().on_teams_signin_verify_state(turn_context) - - async def on_teams_file_consent(self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse): + + async def on_teams_file_consent( + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, + ): self.record.append("on_teams_file_consent") - return await super().on_teams_file_consent(turn_context, file_consent_card_response) - + return await super().on_teams_file_consent( + turn_context, file_consent_card_response + ) + async def on_teams_file_consent_accept_activity( - self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, ): self.record.append("on_teams_file_consent_accept_activity") - return await super().on_teams_file_consent_accept_activity(turn_context, file_consent_card_response) + return await super().on_teams_file_consent_accept_activity( + turn_context, file_consent_card_response + ) async def on_teams_file_consent_decline_activity( - self, turn_context: TurnContext, file_consent_card_response: FileConsentCardResponse + self, + turn_context: TurnContext, + file_consent_card_response: FileConsentCardResponse, ): self.record.append("on_teams_file_consent_decline_activity") - return await super().on_teams_file_consent_decline_activity(turn_context, file_consent_card_response) + return await super().on_teams_file_consent_decline_activity( + turn_context, file_consent_card_response + ) async def on_teams_o365_connector_card_action( self, turn_context: TurnContext, query: O365ConnectorCardActionQuery ): self.record.append("on_teams_o365_connector_card_action") return await super().on_teams_o365_connector_card_action(turn_context, query) - + async def on_teams_app_based_link_query( self, turn_context: TurnContext, query: AppBasedLinkQuery ): self.record.append("on_teams_app_based_link_query") return await super().on_teams_app_based_link_query(turn_context, query) - + async def on_teams_messaging_extension_query( self, turn_context: TurnContext, query: MessagingExtensionQuery ): @@ -130,61 +156,86 @@ async def on_teams_messaging_extension_submit_action_dispatch( self, turn_context: TurnContext, action: MessagingExtensionAction ): self.record.append("on_teams_messaging_extension_submit_action_dispatch") - return await super().on_teams_messaging_extension_submit_action_dispatch(turn_context, action) + return await super().on_teams_messaging_extension_submit_action_dispatch( + turn_context, action + ) async def on_teams_messaging_extension_submit_action_activity( self, turn_context: TurnContext, action: MessagingExtensionAction ): self.record.append("on_teams_messaging_extension_submit_action_activity") - return await super().on_teams_messaging_extension_submit_action_activity(turn_context, action) + return await super().on_teams_messaging_extension_submit_action_activity( + turn_context, action + ) async def on_teams_messaging_extension_bot_message_preview_edit_activity( self, turn_context: TurnContext, action: MessagingExtensionAction ): - self.record.append("on_teams_messaging_extension_bot_message_preview_edit_activity") - return await super().on_teams_messaging_extension_bot_message_preview_edit_activity(turn_context, action) - + self.record.append( + "on_teams_messaging_extension_bot_message_preview_edit_activity" + ) + return await super().on_teams_messaging_extension_bot_message_preview_edit_activity( + turn_context, action + ) + async def on_teams_messaging_extension_bot_message_send_activity( self, turn_context: TurnContext, action: MessagingExtensionAction ): self.record.append("on_teams_messaging_extension_bot_message_send_activity") - return await super().on_teams_messaging_extension_bot_message_send_activity(turn_context, action) + return await super().on_teams_messaging_extension_bot_message_send_activity( + turn_context, action + ) async def on_teams_messaging_extension_fetch_task( self, turn_context: TurnContext, action: MessagingExtensionAction ): self.record.append("on_teams_messaging_extension_fetch_task") - return await super().on_teams_messaging_extension_fetch_task(turn_context, action) + return await super().on_teams_messaging_extension_fetch_task( + turn_context, action + ) async def on_teams_messaging_extension_configuration_query_settings_url( self, turn_context: TurnContext, query: MessagingExtensionQuery ): - self.record.append("on_teams_messaging_extension_configuration_query_settings_url") - return await super().on_teams_messaging_extension_configuration_query_settings_url(turn_context, query) + self.record.append( + "on_teams_messaging_extension_configuration_query_settings_url" + ) + return await super().on_teams_messaging_extension_configuration_query_settings_url( + turn_context, query + ) async def on_teams_messaging_extension_configuration_setting( self, turn_context: TurnContext, settings ): self.record.append("on_teams_messaging_extension_configuration_setting") - return await super().on_teams_messaging_extension_configuration_setting(turn_context, settings) + return await super().on_teams_messaging_extension_configuration_setting( + turn_context, settings + ) async def on_teams_messaging_extension_card_button_clicked( self, turn_context: TurnContext, card_data ): self.record.append("on_teams_messaging_extension_card_button_clicked") - return await super().on_teams_messaging_extension_card_button_clicked(turn_context, card_data) + return await super().on_teams_messaging_extension_card_button_clicked( + turn_context, card_data + ) async def on_teams_task_module_fetch( self, turn_context: TurnContext, task_module_request ): self.record.append("on_teams_task_module_fetch") - return await super().on_teams_task_module_fetch(turn_context, task_module_request) + return await super().on_teams_task_module_fetch( + turn_context, task_module_request + ) async def on_teams_task_module_submit( # pylint: disable=unused-argument self, turn_context: TurnContext, task_module_request: TaskModuleRequest ): self.record.append("on_teams_task_module_submit") - return await super().on_teams_task_module_submit(turn_context, task_module_request) + return await super().on_teams_task_module_submit( + turn_context, task_module_request + ) + class NotImplementedAdapter(BotAdapter): async def delete_activity( @@ -200,19 +251,17 @@ async def send_activities( async def update_activity(self, context: TurnContext, activity: Activity): raise NotImplementedError() + class TestTeamsActivityHandler(aiounittest.AsyncTestCase): async def test_on_teams_channel_created_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "channelCreated", - "channel": { - "id": "asdfqwerty", - "name" : "new_channel" - } - }, - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={ + "eventType": "channelCreated", + "channel": {"id": "asdfqwerty", "name": "new_channel"}, + }, + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -225,19 +274,16 @@ async def test_on_teams_channel_created_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_channel_created_activity" - + async def test_on_teams_channel_renamed_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "channelRenamed", - "channel": { - "id": "asdfqwerty", - "name" : "new_channel" - } - }, - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={ + "eventType": "channelRenamed", + "channel": {"id": "asdfqwerty", "name": "new_channel"}, + }, + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -250,19 +296,16 @@ async def test_on_teams_channel_renamed_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_channel_renamed_activity" - + async def test_on_teams_channel_deleted_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "channelDeleted", - "channel": { - "id": "asdfqwerty", - "name" : "new_channel" - } - }, - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={ + "eventType": "channelDeleted", + "channel": {"id": "asdfqwerty", "name": "new_channel"}, + }, + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -275,19 +318,16 @@ async def test_on_teams_channel_deleted_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_channel_deleted_activity" - + async def test_on_teams_team_renamed_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "teamRenamed", - "team": { - "id": "team_id_1", - "name" : "new_team_name" - } - }, - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={ + "eventType": "teamRenamed", + "team": {"id": "team_id_1", "name": "new_team_name"}, + }, + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -300,16 +340,21 @@ async def test_on_teams_team_renamed_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_team_renamed_activity" - + async def test_on_teams_members_added_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "teamMemberAdded" - }, - members_added = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={"eventType": "teamMemberAdded"}, + members_added=[ + ChannelAccount( + id="123", + name="test_user", + aad_object_id="asdfqwerty", + role="tester", + ) + ], + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -322,16 +367,21 @@ async def test_on_teams_members_added_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_members_added_activity" - + async def test_on_teams_members_removed_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.conversation_update, - channel_data = { - "eventType": "teamMemberRemoved" - }, - members_removed = [ChannelAccount(id="123", name="test_user", aad_object_id="asdfqwerty", role="tester")], - channel_id = Channels.ms_teams + type=ActivityTypes.conversation_update, + channel_data={"eventType": "teamMemberRemoved"}, + members_removed=[ + ChannelAccount( + id="123", + name="test_user", + aad_object_id="asdfqwerty", + role="tester", + ) + ], + channel_id=Channels.ms_teams, ) turn_context = TurnContext(NotImplementedAdapter(), activity) @@ -344,13 +394,10 @@ async def test_on_teams_members_removed_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_conversation_update_activity" assert bot.record[1] == "on_teams_members_removed_activity" - + async def test_on_signin_verify_state(self): - #arrange - activity = Activity( - type = ActivityTypes.invoke, - name = "signin/verifyState" - ) + # arrange + activity = Activity(type=ActivityTypes.invoke, name="signin/verifyState") turn_context = TurnContext(SimpleAdapter(), activity) @@ -362,13 +409,13 @@ async def test_on_signin_verify_state(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_signin_verify_state" - + async def test_on_file_consent_accept_activity(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.invoke, - name = "fileConsent/invoke", - value = {"action" : "accept"} + type=ActivityTypes.invoke, + name="fileConsent/invoke", + value={"action": "accept"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -382,13 +429,13 @@ async def test_on_file_consent_accept_activity(self): assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_file_consent" assert bot.record[2] == "on_teams_file_consent_accept_activity" - + async def test_on_file_consent_decline_activity(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "fileConsent/invoke", - value = {"action" : "decline"} + type=ActivityTypes.invoke, + name="fileConsent/invoke", + value={"action": "decline"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -402,13 +449,13 @@ async def test_on_file_consent_decline_activity(self): assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_file_consent" assert bot.record[2] == "on_teams_file_consent_decline_activity" - + async def test_on_file_consent_bad_action_activity(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "fileConsent/invoke", - value = {"action" : "bad_action"} + type=ActivityTypes.invoke, + name="fileConsent/invoke", + value={"action": "bad_action"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -421,16 +468,13 @@ async def test_on_file_consent_bad_action_activity(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_file_consent" - + async def test_on_teams_o365_connector_card_action(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.invoke, - name = "actionableMessage/executeAction", - value = { - "body": "body_here", - "actionId": "action_id_here" - } + type=ActivityTypes.invoke, + name="actionableMessage/executeAction", + value={"body": "body_here", "actionId": "action_id_here"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -443,15 +487,13 @@ async def test_on_teams_o365_connector_card_action(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_o365_connector_card_action" - + async def test_on_app_based_link_query(self): - #arrange + # arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/query", - value = { - "url": "http://www.test.com" - } + type=ActivityTypes.invoke, + name="composeExtension/query", + value={"url": "http://www.test.com"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -464,21 +506,21 @@ async def test_on_app_based_link_query(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_query" - + async def test_on_teams_messaging_extension_bot_message_preview_edit_activity(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/submitAction", - value = { - "data": {"key": "value"}, - "context": {"theme": "dark"}, - "comamndId": "test_command", - "commandContext": "command_context_test", - "botMessagePreviewAction": "edit", - "botActivityPreview": [Activity().serialize()], - "messagePayload": MessageActionsPayload().serialize(), - } + type=ActivityTypes.invoke, + name="composeExtension/submitAction", + value={ + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "edit", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -491,22 +533,25 @@ async def test_on_teams_messaging_extension_bot_message_preview_edit_activity(se assert len(bot.record) == 3 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" - assert bot.record[2] == "on_teams_messaging_extension_bot_message_preview_edit_activity" + assert ( + bot.record[2] + == "on_teams_messaging_extension_bot_message_preview_edit_activity" + ) async def test_on_teams_messaging_extension_bot_message_send_activity(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/submitAction", - value = { - "data": {"key": "value"}, - "context": {"theme": "dark"}, - "comamndId": "test_command", - "commandContext": "command_context_test", - "botMessagePreviewAction": "send", - "botActivityPreview": [Activity().serialize()], - "messagePayload": MessageActionsPayload().serialize(), - } + type=ActivityTypes.invoke, + name="composeExtension/submitAction", + value={ + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "send", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -520,21 +565,23 @@ async def test_on_teams_messaging_extension_bot_message_send_activity(self): assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" assert bot.record[2] == "on_teams_messaging_extension_bot_message_send_activity" - - async def test_on_teams_messaging_extension_bot_message_send_activity_with_none(self): - # Arrange + + async def test_on_teams_messaging_extension_bot_message_send_activity_with_none( + self, + ): + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/submitAction", - value = { - "data": {"key": "value"}, - "context": {"theme": "dark"}, - "comamndId": "test_command", - "commandContext": "command_context_test", - "botMessagePreviewAction": None, - "botActivityPreview": [Activity().serialize()], - "messagePayload": MessageActionsPayload().serialize(), - } + type=ActivityTypes.invoke, + name="composeExtension/submitAction", + value={ + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": None, + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -548,21 +595,23 @@ async def test_on_teams_messaging_extension_bot_message_send_activity_with_none( assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" assert bot.record[2] == "on_teams_messaging_extension_submit_action_activity" - - async def test_on_teams_messaging_extension_bot_message_send_activity_with_empty_string(self): - # Arrange + + async def test_on_teams_messaging_extension_bot_message_send_activity_with_empty_string( + self, + ): + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/submitAction", - value = { - "data": {"key": "value"}, - "context": {"theme": "dark"}, - "comamndId": "test_command", - "commandContext": "command_context_test", - "botMessagePreviewAction": "", - "botActivityPreview": [Activity().serialize()], - "messagePayload": MessageActionsPayload().serialize(), - } + type=ActivityTypes.invoke, + name="composeExtension/submitAction", + value={ + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -576,21 +625,21 @@ async def test_on_teams_messaging_extension_bot_message_send_activity_with_empty assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_submit_action_dispatch" assert bot.record[2] == "on_teams_messaging_extension_submit_action_activity" - + async def test_on_teams_messaging_extension_fetch_task(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/fetchTask", - value = { - "data": {"key": "value"}, - "context": {"theme": "dark"}, - "comamndId": "test_command", - "commandContext": "command_context_test", - "botMessagePreviewAction": "message_action", - "botActivityPreview": [Activity().serialize()], - "messagePayload": MessageActionsPayload().serialize(), - } + type=ActivityTypes.invoke, + name="composeExtension/fetchTask", + value={ + "data": {"key": "value"}, + "context": {"theme": "dark"}, + "comamndId": "test_command", + "commandContext": "command_context_test", + "botMessagePreviewAction": "message_action", + "botActivityPreview": [Activity().serialize()], + "messagePayload": MessageActionsPayload().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -603,18 +652,18 @@ async def test_on_teams_messaging_extension_fetch_task(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_fetch_task" - + async def test_on_teams_messaging_extension_configuration_query_settings_url(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/querySettingUrl", - value = { - "comamndId": "test_command", - "parameters": [], - "messagingExtensionQueryOptions": {"skip": 1, "count": 1}, - "state": "state_string", - } + type=ActivityTypes.invoke, + name="composeExtension/querySettingUrl", + value={ + "comamndId": "test_command", + "parameters": [], + "messagingExtensionQueryOptions": {"skip": 1, "count": 1}, + "state": "state_string", + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -626,16 +675,17 @@ async def test_on_teams_messaging_extension_configuration_query_settings_url(sel # Assert assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" - assert bot.record[1] == "on_teams_messaging_extension_configuration_query_settings_url" - + assert ( + bot.record[1] + == "on_teams_messaging_extension_configuration_query_settings_url" + ) + async def test_on_teams_messaging_extension_configuration_setting(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/setting", - value = { - "key": "value" - } + type=ActivityTypes.invoke, + name="composeExtension/setting", + value={"key": "value"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -648,15 +698,13 @@ async def test_on_teams_messaging_extension_configuration_setting(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_configuration_setting" - + async def test_on_teams_messaging_extension_card_button_clicked(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "composeExtension/onCardButtonClicked", - value = { - "key": "value" - } + type=ActivityTypes.invoke, + name="composeExtension/onCardButtonClicked", + value={"key": "value"}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -669,16 +717,16 @@ async def test_on_teams_messaging_extension_card_button_clicked(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_messaging_extension_card_button_clicked" - + async def test_on_teams_task_module_fetch(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "task/fetch", - value = { - "data": {"key": "value"}, - "context": TaskModuleRequestContext().serialize() - } + type=ActivityTypes.invoke, + name="task/fetch", + value={ + "data": {"key": "value"}, + "context": TaskModuleRequestContext().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -691,16 +739,16 @@ async def test_on_teams_task_module_fetch(self): assert len(bot.record) == 2 assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_task_module_fetch" - + async def test_on_teams_task_module_submit(self): - # Arrange + # Arrange activity = Activity( - type = ActivityTypes.invoke, - name = "task/submit", - value = { - "data": {"key": "value"}, - "context": TaskModuleRequestContext().serialize() - } + type=ActivityTypes.invoke, + name="task/submit", + value={ + "data": {"key": "value"}, + "context": TaskModuleRequestContext().serialize(), + }, ) turn_context = TurnContext(SimpleAdapter(), activity) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py index f348245af..e80cee5f9 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models.py @@ -1544,7 +1544,7 @@ def __init__(self, **kwargs): self.given_name = kwargs.get("given_name", None) self.surname = kwargs.get("surname", None) self.email = kwargs.get("email", None) - self.userPrincipalName = kwargs.get("userPrincipalName", None) + self.user_principal_name = kwargs.get("userPrincipalName", None) class TeamsChannelData(Model): diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 7d7dcbdeb..0f3a075a6 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -1132,7 +1132,7 @@ class O365ConnectorCardActionQuery(Model): def __init__(self, *, body: str = None, actionId: str = None, **kwargs) -> None: super(O365ConnectorCardActionQuery, self).__init__(**kwargs) self.body = body - # This is how it comes in from Teams + # This is how it comes in from Teams self.action_id = actionId From d9d0fe4a08edb640ce10ad396dcb1252cf407798 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Wed, 4 Dec 2019 10:07:42 -0800 Subject: [PATCH 7/8] removing init and adding simple_adapter --- libraries/botbuilder-core/tests/__init__.py | 3 - .../botbuilder-core/tests/teams/__init__.py | 0 .../tests/teams/simple_adapter.py | 60 +++++++++++++++++++ .../teams/test_teams_activity_handler.py | 2 +- 4 files changed, 61 insertions(+), 4 deletions(-) delete mode 100644 libraries/botbuilder-core/tests/__init__.py delete mode 100644 libraries/botbuilder-core/tests/teams/__init__.py create mode 100644 libraries/botbuilder-core/tests/teams/simple_adapter.py diff --git a/libraries/botbuilder-core/tests/__init__.py b/libraries/botbuilder-core/tests/__init__.py deleted file mode 100644 index 6fff60cf5..000000000 --- a/libraries/botbuilder-core/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .simple_adapter import SimpleAdapter - -__all__ = ["SimpleAdapter"] diff --git a/libraries/botbuilder-core/tests/teams/__init__.py b/libraries/botbuilder-core/tests/teams/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/libraries/botbuilder-core/tests/teams/simple_adapter.py b/libraries/botbuilder-core/tests/teams/simple_adapter.py new file mode 100644 index 000000000..a80fa29b3 --- /dev/null +++ b/libraries/botbuilder-core/tests/teams/simple_adapter.py @@ -0,0 +1,60 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import unittest +from typing import List +from botbuilder.core import BotAdapter, TurnContext +from botbuilder.schema import Activity, ConversationReference, ResourceResponse + + +class SimpleAdapter(BotAdapter): + # pylint: disable=unused-argument + + def __init__(self, call_on_send=None, call_on_update=None, call_on_delete=None): + super(SimpleAdapter, self).__init__() + self.test_aux = unittest.TestCase("__init__") + self._call_on_send = call_on_send + self._call_on_update = call_on_update + self._call_on_delete = call_on_delete + + async def delete_activity( + self, context: TurnContext, reference: ConversationReference + ): + self.test_aux.assertIsNotNone( + reference, "SimpleAdapter.delete_activity: missing reference" + ) + if self._call_on_delete is not None: + self._call_on_delete(reference) + + async def send_activities( + self, context: TurnContext, activities: List[Activity] + ) -> List[ResourceResponse]: + self.test_aux.assertIsNotNone( + activities, "SimpleAdapter.delete_activity: missing reference" + ) + self.test_aux.assertTrue( + len(activities) > 0, + "SimpleAdapter.send_activities: empty activities array.", + ) + + if self._call_on_send is not None: + self._call_on_send(activities) + responses = [] + + for activity in activities: + responses.append(ResourceResponse(id=activity.id)) + + return responses + + async def update_activity(self, context: TurnContext, activity: Activity): + self.test_aux.assertIsNotNone( + activity, "SimpleAdapter.update_activity: missing activity" + ) + if self._call_on_update is not None: + self._call_on_update(activity) + + return ResourceResponse(activity.id) + + async def process_request(self, activity, handler): + context = TurnContext(self, activity) + return self.run_pipeline(context, handler) diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index 06152f21b..c1485e090 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -24,7 +24,7 @@ TeamsChannelAccount, ) from botframework.connector import Channels -from .. import SimpleAdapter +from simple_adapter import SimpleAdapter class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): From a61dbe9f302e7a229af644989b21a28b74f077b8 Mon Sep 17 00:00:00 2001 From: virtual-josh Date: Wed, 4 Dec 2019 10:17:00 -0800 Subject: [PATCH 8/8] fixing black --- .../botbuilder-core/tests/teams/test_teams_activity_handler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py index c1485e090..540d5742b 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -26,6 +26,7 @@ from botframework.connector import Channels from simple_adapter import SimpleAdapter + class TestingTeamsActivityHandler(TeamsActivityHandler): def __init__(self): self.record: List[str] = []