From 06f401e50bf9d3f08243fffd04c68657153d5cd6 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Mon, 1 Feb 2021 00:20:20 -0800 Subject: [PATCH 1/8] Some teams models ported --- .../botbuilder/schema/teams/_models_py3.py | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index e4d16baf8..0d26f9e76 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -10,6 +10,216 @@ ) +class TabContext(Model): + """ + Current tab request context, i.e., the current theme. + + :param theme: Gets or sets the current user's theme. + :type theme: str + """ + + _attribute_map = { + "theme": {"key": "theme", "type": "str"}, + } + + def __init__(self, *, theme=None, **kwargs) -> None: + super(TabContext, self).__init__(**kwargs) + self.theme = theme + self._custom_init() + + def _custom_init(self): + return + + +class TabEntityContext(Model): + """ + Current TabRequest entity context, or 'tabEntityId'. + + :param tab_entity_id: Gets or sets the entity id of the tab. + :type tab_entity_id: str + """ + + _attribute_map = { + "tab_entity_id": {"key": "tabEntityId", "type": "str"}, + } + + def __init__(self, *, tab_entity_id=None, **kwargs) -> None: + super(TabEntityContext, self).__init__(**kwargs) + self.tab_entity_id = tab_entity_id + self._custom_init() + + def _custom_init(self): + return + + +class TabRequest(Model): + """ + Invoke ('tab/fetch') request value payload. + + :param tab_entity_context: Gets or sets current tab entity request context. + :type tab_entity_context: + ~botframework.connector.teams.models.TabEntityContext + :param context: Gets or sets current tab entity request context. + :type context: + ~botframework.connector.teams.models.TabContext + :param state: Gets or sets state, which is the magic code for OAuth Flow. + :type state: str + """ + + _attribute_map = { + "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "context": {"key": "context", "type": "TabContext"}, + "state": {"key": "state", "type": "str"}, + } + + def __init__( + self, *, tab_entity_context=None, context=None, state=None, **kwargs + ) -> None: + super(TabRequest, self).__init__(**kwargs) + self.tab_entity_context = tab_entity_context + self.context = context + self.state = state + self._custom_init() + + def _custom_init(self): + return + + +class TabResponseCard(Model): + """ + Envelope for cards for a Tab request. + + :param card: Gets or sets adaptive card for this card tab response. + :type card: object + """ + + _attribute_map = { + "card": {"key": "card", "type": "object"}, + } + + def __init__(self, *, card=None, **kwargs) -> None: + super(TabResponseCard, self).__init__(**kwargs) + self.card = card + self._custom_init() + + def _custom_init(self): + return + + +class TabResponseCards(Model): + """ + Envelope for cards for a TabResponse. + + :param cards: Gets or sets adaptive card for this card tab response. + :type cards: list[object] + """ + + _attribute_map = { + "cards": {"key": "cards", "type": "[object]"}, + } + + def __init__(self, *, cards=None, **kwargs) -> None: + super(TabResponseCards, self).__init__(**kwargs) + self.cards = cards + self._custom_init() + + def _custom_init(self): + return + + +class TabResponsePayload(Model): + """ + Initializes a new instance of the TabResponsePayload class. + + :param type: Gets or sets choice of action options when responding to the + tab/fetch message. Possible values include: 'continue', 'auth' or 'silentAuth' + :type type: str + :param value: Gets or sets the TabResponseCards when responding to + tab/fetch activity with type of 'continue'. + :type value: TabResponseCards + :param suggested_actions: Gets or sets the Suggested Actions for this card tab. + :type suggested_actions: TabSuggestedActions + """ + + _attribute_map = { + "type": {"key": "type", "type": "str"}, + "value": {"key": "value", "type": "TabResponseCards"}, + "suggested_actions": {"key": "suggestedActions", "type": "TabSuggestedActions"}, + } + + def __init__( + self, *, type=None, value=None, suggested_actions=None, **kwargs + ) -> None: + super(TabResponsePayload, self).__init__(**kwargs) + self.type = type + self.value = value + self.suggested_actions = suggested_actions + self._custom_init() + + def _custom_init(self): + return + + +class TabSumit(Model): + """ + Invoke ('tab/submit') request value payload. + + :param tab_entity_context: Gets or sets current tab entity request context. + :type tab_entity_context: + ~botframework.connector.teams.models.TabEntityContext + :param context: Gets or sets current tab entity request context. + :type context: + ~botframework.connector.teams.models.TabContext + :param data: User input data. Free payload containing properties of key-value pairs. + :type data: + ~botframework.connector.teams.models.TabSubmitData + """ + + _attribute_map = { + "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "context": {"key": "context", "type": "TabContext"}, + "data": {"key": "data", "type": "TabSubmitData"}, + } + + def __init__( + self, *, tab_entity_context=None, context=None, data=None, **kwargs + ) -> None: + super(TabSumit, self).__init__(**kwargs) + self.tab_entity_context = tab_entity_context + self.context = context + self.data = data + self._custom_init() + + def _custom_init(self): + return + + +class TabSubmitData(Model): + """ + Invoke ('tab/submit') request value payload data. + + :param type: Currently, 'tab/submit'. + :type type: str + :param properties: Gets or sets properties that are not otherwise defined by the TabSubmit + type but that might appear in the serialized REST JSON object. + :type properties: object + """ + + _attribute_map = { + "type": {"key": "type", "type": "str"}, + "properties": {"key": "properties", "type": "object"}, + } + + def __init__(self, *, type=None, properties=None, **kwargs) -> None: + super(TabSubmitData, self).__init__(**kwargs) + self.type = type + self.properties = properties + self._custom_init() + + def _custom_init(self): + return + + class TaskModuleRequest(Model): """Task module invoke request value payload. From b57eacb79a09266be307ef782e152e9d299dc14a Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Mon, 1 Feb 2021 20:30:09 -0800 Subject: [PATCH 2/8] Teams AH changes and schema updates --- .../core/teams/teams_activity_handler.py | 48 ++ .../botbuilder/schema/teams/__init__.py | 18 + .../botbuilder/schema/teams/_models_py3.py | 460 ++++++++++-------- 3 files changed, 336 insertions(+), 190 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 5b2673a22..1087267bc 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -23,6 +23,8 @@ O365ConnectorCardActionQuery, TaskModuleRequest, TaskModuleResponse, + TabRequest, + TabSubmit, ) from botframework.connector import Channels from ..serializer_helper import deserializer_helper @@ -163,6 +165,26 @@ async def on_invoke_activity(self, turn_context: TurnContext) -> InvokeResponse: ) ) + if turn_context.activity.name == "tab/fetch": + return self._create_invoke_response( + await self.on_teams_task_module_submit( + turn_context, + deserializer_helper( + TaskModuleRequest, turn_context.activity.value + ), + ) + ) + + if turn_context.activity.name == "tab/submit": + return self._create_invoke_response( + await self.on_teams_task_module_submit( + turn_context, + deserializer_helper( + TaskModuleRequest, turn_context.activity.value + ), + ) + ) + return await super().on_invoke_activity(turn_context) except _InvokeResponseException as invoke_exception: @@ -835,3 +857,29 @@ async def on_teams_channel_restored( # pylint: disable=unused-argument :returns: A task that represents the work queued to execute. """ return + + async def on_teams_tab_fetch( # pylint: disable=unused-argument + self, turn_context: TurnContext, tab_request: TabRequest + ): + """ + Override this in a derived class to provide logic for when a tab is fetched. + + :param turn_context: A context object for this turn. + :param tab_request: The tab invoke request value payload. + + :returns: A Tab Response for the request. + """ + return + + async def on_teams_tab_submit( # pylint: disable=unused-argument + self, turn_context: TurnContext, tab_submit: TabSubmit + ): + """ + Override this in a derived class to provide logic for when a tab is submitted. + + :param turn_context: A context object for this turn. + :param tab_submit: The tab submit invoke request value payload. + + :returns: A Tab Response for the request. + """ + return diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py index b6116a3ec..28a70f41a 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py @@ -62,6 +62,15 @@ from ._models_py3 import TeamsMeetingParticipant from ._models_py3 import MeetingParticipantInfo from ._models_py3 import CacheInfo +from ._models_py3 import TabContext +from ._models_py3 import TabRequest +from ._models_py3 import TabResponseCard +from ._models_py3 import TabResponseCards +from ._models_py3 import TabResponsePayload +from ._models_py3 import TabSubmit +from ._models_py3 import TabSubmitData +from ._models_py3 import TabSuggestedActions +from ._models_py3 import TaskModuleCardResponse __all__ = [ "AppBasedLinkQuery", @@ -125,4 +134,13 @@ "TeamsMeetingParticipant", "MeetingParticipantInfo", "CacheInfo", + "TabContext", + "TabRequest", + "TabResponseCard", + "TabResponseCards", + "TabResponsePayload", + "TabSubmit", + "TabSubmitData", + "TabSuggestedActions", + "TaskModuleCardResponse", ] diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 0d26f9e76..2fe146de6 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -10,27 +10,6 @@ ) -class TabContext(Model): - """ - Current tab request context, i.e., the current theme. - - :param theme: Gets or sets the current user's theme. - :type theme: str - """ - - _attribute_map = { - "theme": {"key": "theme", "type": "str"}, - } - - def __init__(self, *, theme=None, **kwargs) -> None: - super(TabContext, self).__init__(**kwargs) - self.theme = theme - self._custom_init() - - def _custom_init(self): - return - - class TabEntityContext(Model): """ Current TabRequest entity context, or 'tabEntityId'. @@ -52,174 +31,6 @@ def _custom_init(self): return -class TabRequest(Model): - """ - Invoke ('tab/fetch') request value payload. - - :param tab_entity_context: Gets or sets current tab entity request context. - :type tab_entity_context: - ~botframework.connector.teams.models.TabEntityContext - :param context: Gets or sets current tab entity request context. - :type context: - ~botframework.connector.teams.models.TabContext - :param state: Gets or sets state, which is the magic code for OAuth Flow. - :type state: str - """ - - _attribute_map = { - "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, - "context": {"key": "context", "type": "TabContext"}, - "state": {"key": "state", "type": "str"}, - } - - def __init__( - self, *, tab_entity_context=None, context=None, state=None, **kwargs - ) -> None: - super(TabRequest, self).__init__(**kwargs) - self.tab_entity_context = tab_entity_context - self.context = context - self.state = state - self._custom_init() - - def _custom_init(self): - return - - -class TabResponseCard(Model): - """ - Envelope for cards for a Tab request. - - :param card: Gets or sets adaptive card for this card tab response. - :type card: object - """ - - _attribute_map = { - "card": {"key": "card", "type": "object"}, - } - - def __init__(self, *, card=None, **kwargs) -> None: - super(TabResponseCard, self).__init__(**kwargs) - self.card = card - self._custom_init() - - def _custom_init(self): - return - - -class TabResponseCards(Model): - """ - Envelope for cards for a TabResponse. - - :param cards: Gets or sets adaptive card for this card tab response. - :type cards: list[object] - """ - - _attribute_map = { - "cards": {"key": "cards", "type": "[object]"}, - } - - def __init__(self, *, cards=None, **kwargs) -> None: - super(TabResponseCards, self).__init__(**kwargs) - self.cards = cards - self._custom_init() - - def _custom_init(self): - return - - -class TabResponsePayload(Model): - """ - Initializes a new instance of the TabResponsePayload class. - - :param type: Gets or sets choice of action options when responding to the - tab/fetch message. Possible values include: 'continue', 'auth' or 'silentAuth' - :type type: str - :param value: Gets or sets the TabResponseCards when responding to - tab/fetch activity with type of 'continue'. - :type value: TabResponseCards - :param suggested_actions: Gets or sets the Suggested Actions for this card tab. - :type suggested_actions: TabSuggestedActions - """ - - _attribute_map = { - "type": {"key": "type", "type": "str"}, - "value": {"key": "value", "type": "TabResponseCards"}, - "suggested_actions": {"key": "suggestedActions", "type": "TabSuggestedActions"}, - } - - def __init__( - self, *, type=None, value=None, suggested_actions=None, **kwargs - ) -> None: - super(TabResponsePayload, self).__init__(**kwargs) - self.type = type - self.value = value - self.suggested_actions = suggested_actions - self._custom_init() - - def _custom_init(self): - return - - -class TabSumit(Model): - """ - Invoke ('tab/submit') request value payload. - - :param tab_entity_context: Gets or sets current tab entity request context. - :type tab_entity_context: - ~botframework.connector.teams.models.TabEntityContext - :param context: Gets or sets current tab entity request context. - :type context: - ~botframework.connector.teams.models.TabContext - :param data: User input data. Free payload containing properties of key-value pairs. - :type data: - ~botframework.connector.teams.models.TabSubmitData - """ - - _attribute_map = { - "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, - "context": {"key": "context", "type": "TabContext"}, - "data": {"key": "data", "type": "TabSubmitData"}, - } - - def __init__( - self, *, tab_entity_context=None, context=None, data=None, **kwargs - ) -> None: - super(TabSumit, self).__init__(**kwargs) - self.tab_entity_context = tab_entity_context - self.context = context - self.data = data - self._custom_init() - - def _custom_init(self): - return - - -class TabSubmitData(Model): - """ - Invoke ('tab/submit') request value payload data. - - :param type: Currently, 'tab/submit'. - :type type: str - :param properties: Gets or sets properties that are not otherwise defined by the TabSubmit - type but that might appear in the serialized REST JSON object. - :type properties: object - """ - - _attribute_map = { - "type": {"key": "type", "type": "str"}, - "properties": {"key": "properties", "type": "object"}, - } - - def __init__(self, *, type=None, properties=None, **kwargs) -> None: - super(TabSubmitData, self).__init__(**kwargs) - self.type = type - self.properties = properties - self._custom_init() - - def _custom_init(self): - return - - class TaskModuleRequest(Model): """Task module invoke request value payload. @@ -228,17 +39,24 @@ class TaskModuleRequest(Model): :param context: Current user context, i.e., the current theme :type context: ~botframework.connector.teams.models.TaskModuleRequestContext + :param tab_entity_context: Gets or sets current tab request context. + :type tab_entity_context: + ~botframework.connector.teams.models.TabEntityContext """ _attribute_map = { "data": {"key": "data", "type": "object"}, "context": {"key": "context", "type": "TaskModuleRequestContext"}, + "tab_entity_context": {"key": "tabContext", "type": "TabEntityContext"}, } - def __init__(self, *, data=None, context=None, **kwargs) -> None: + def __init__( + self, *, data=None, context=None, tab_entity_context=None, **kwargs + ) -> None: super(TaskModuleRequest, self).__init__(**kwargs) self.data = data self.context = context + self.tab_entity_context = tab_entity_context class AppBasedLinkQuery(Model): @@ -2268,3 +2086,265 @@ def __init__( self.user = user self.meeting = meeting self.conversation = conversation + + +class TabContext(Model): + """ + Current tab request context, i.e., the current theme. + + :param theme: Gets or sets the current user's theme. + :type theme: str + """ + + _attribute_map = { + "theme": {"key": "theme", "type": "str"}, + } + + def __init__(self, *, theme=None, **kwargs) -> None: + super(TabContext, self).__init__(**kwargs) + self.theme = theme + self._custom_init() + + def _custom_init(self): + return + + +class TabRequest(Model): + """ + Invoke ('tab/fetch') request value payload. + + :param tab_entity_context: Gets or sets current tab entity request context. + :type tab_entity_context: + ~botframework.connector.teams.models.TabEntityContext + :param context: Gets or sets current tab entity request context. + :type context: + ~botframework.connector.teams.models.TabContext + :param state: Gets or sets state, which is the magic code for OAuth Flow. + :type state: str + """ + + _attribute_map = { + "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "context": {"key": "context", "type": "TabContext"}, + "state": {"key": "state", "type": "str"}, + } + + def __init__( + self, *, tab_entity_context=None, context=None, state=None, **kwargs + ) -> None: + super(TabRequest, self).__init__(**kwargs) + self.tab_entity_context = tab_entity_context + self.context = context + self.state = state + self._custom_init() + + def _custom_init(self): + return + + +class TabResponseCard(Model): + """ + Envelope for cards for a Tab request. + + :param card: Gets or sets adaptive card for this card tab response. + :type card: object + """ + + _attribute_map = { + "card": {"key": "card", "type": "object"}, + } + + def __init__(self, *, card=None, **kwargs) -> None: + super(TabResponseCard, self).__init__(**kwargs) + self.card = card + self._custom_init() + + def _custom_init(self): + return + + +class TabResponseCards(Model): + """ + Envelope for cards for a TabResponse. + + :param cards: Gets or sets adaptive card for this card tab response. + :type cards: list[object] + """ + + _attribute_map = { + "cards": {"key": "cards", "type": "[object]"}, + } + + def __init__(self, *, cards=None, **kwargs) -> None: + super(TabResponseCards, self).__init__(**kwargs) + self.cards = cards + self._custom_init() + + def _custom_init(self): + return + + +class TabResponsePayload(Model): + """ + Initializes a new instance of the TabResponsePayload class. + + :param type: Gets or sets choice of action options when responding to the + tab/fetch message. Possible values include: 'continue', 'auth' or 'silentAuth' + :type type: str + :param value: Gets or sets the TabResponseCards when responding to + tab/fetch activity with type of 'continue'. + :type value: TabResponseCards + :param suggested_actions: Gets or sets the Suggested Actions for this card tab. + :type suggested_actions: TabSuggestedActions + """ + + _attribute_map = { + "type": {"key": "type", "type": "str"}, + "value": {"key": "value", "type": "TabResponseCards"}, + "suggested_actions": {"key": "suggestedActions", "type": "TabSuggestedActions"}, + } + + def __init__( + self, *, type=None, value=None, suggested_actions=None, **kwargs + ) -> None: + super(TabResponsePayload, self).__init__(**kwargs) + self.type = type + self.value = value + self.suggested_actions = suggested_actions + self._custom_init() + + def _custom_init(self): + return + + +class TabSumit(Model): + """ + Invoke ('tab/submit') request value payload. + + :param tab_entity_context: Gets or sets current tab entity request context. + :type tab_entity_context: + ~botframework.connector.teams.models.TabEntityContext + :param context: Gets or sets current tab entity request context. + :type context: + ~botframework.connector.teams.models.TabContext + :param data: User input data. Free payload containing properties of key-value pairs. + :type data: + ~botframework.connector.teams.models.TabSubmitData + """ + + _attribute_map = { + "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "context": {"key": "context", "type": "TabContext"}, + "data": {"key": "data", "type": "TabSubmitData"}, + } + + def __init__( + self, *, tab_entity_context=None, context=None, data=None, **kwargs + ) -> None: + super(TabSumit, self).__init__(**kwargs) + self.tab_entity_context = tab_entity_context + self.context = context + self.data = data + self._custom_init() + + def _custom_init(self): + return + + +class TabSubmitData(Model): + """ + Invoke ('tab/submit') request value payload data. + + :param type: Currently, 'tab/submit'. + :type type: str + :param properties: Gets or sets properties that are not otherwise defined by the TabSubmit + type but that might appear in the serialized REST JSON object. + :type properties: object + """ + + _attribute_map = { + "type": {"key": "type", "type": "str"}, + "properties": {"key": "properties", "type": "object"}, + } + + def __init__(self, *, type=None, properties=None, **kwargs) -> None: + super(TabSubmitData, self).__init__(**kwargs) + self.type = type + self.properties = properties + self._custom_init() + + def _custom_init(self): + return + + +class TabSubmit(Model): + """ + Initializes a new instance of the TabSubmit class. + + :param tab_entity_context: Gets or sets current tab entity request context. + :type tab_entity_context: ~botframework.connector.teams.models.TabEntityContext + :param context: Gets or sets current user context, i.e., the current theme. + :type context: ~botframework.connector.teams.models.TabContext + :param data: User input data. Free payload containing properties of key-value pairs. + :type data: ~botframework.connector.teams.models.TabSubmitData + """ + + _attribute_map = { + "tab_entity_context": {"key": "tabContext", "type": "TabEntityContext"}, + "context": {"key": "context", "type": "TabContext"}, + "data": {"key": "data", "type": "TabSubmitData"}, + } + + def __init__( + self, *, tab_entity_context=None, context=None, data=data, **kwargs + ) -> None: + super(TabSubmit, self).__init__(**kwargs) + self.tab_entity_context = tab_entity_context + self.context = context + self.data = data + self._custom_init() + + def _custom_init(self): + return + + +class TabSuggestedActions(Model): + """ + Tab SuggestedActions (Only when type is 'auth' or 'silentAuth'). + + :param actions: Gets or sets adaptive card for this card tab response. + :type actions: list[~botframework.connector.models.CardAction] + """ + + _attribute_map = { + "actions": {"key": "actions", "type": "[CardAction]"}, + } + + def __init__(self, *, actions=None, **kwargs) -> None: + super(TabSuggestedActions, self).__init__(**kwargs) + self.actions = actions + self._custom_init() + + def _custom_init(self): + return + + +class TaskModuleCardResponse(TaskModuleResponseBase): + """ + Tab Response to 'task/submit' from a tab. + + :param value: The JSON for the Adaptive cards to appear in the tab. + :type value: ~botframework.connector.teams.models.TabResponse + """ + + _attribute_map = { + "value": {"key": "value", "type": "TabResponse"}, + } + + def __init__(self, *, value=None, **kwargs) -> None: + super(TaskModuleCardResponse, self).__init__("continue", **kwargs) + self.value = value + self._custom_init() + + def _custom_init(self): + return From 58b77470c623dbe920d1c273b4c1779581e4faf7 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Tue, 2 Feb 2021 14:37:54 -0800 Subject: [PATCH 3/8] Adding unit tests and bug fixing --- .../core/teams/teams_activity_handler.py | 10 +-- .../teams/test_teams_activity_handler.py | 63 +++++++++++++++++++ .../botbuilder/schema/teams/_models_py3.py | 2 +- 3 files changed, 69 insertions(+), 6 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 1087267bc..19d5de29b 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -24,7 +24,7 @@ TaskModuleRequest, TaskModuleResponse, TabRequest, - TabSubmit, + TabSubmit ) from botframework.connector import Channels from ..serializer_helper import deserializer_helper @@ -167,20 +167,20 @@ async def on_invoke_activity(self, turn_context: TurnContext) -> InvokeResponse: if turn_context.activity.name == "tab/fetch": return self._create_invoke_response( - await self.on_teams_task_module_submit( + await self.on_teams_tab_fetch( turn_context, deserializer_helper( - TaskModuleRequest, turn_context.activity.value + TabRequest, turn_context.activity.value ), ) ) if turn_context.activity.name == "tab/submit": return self._create_invoke_response( - await self.on_teams_task_module_submit( + await self.on_teams_tab_submit( turn_context, deserializer_helper( - TaskModuleRequest, turn_context.activity.value + TabSubmit, turn_context.activity.value ), ) ) 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 3a2f2318c..b532a8989 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -27,6 +27,9 @@ TaskModuleRequestContext, TeamInfo, TeamsChannelAccount, + TabRequest, + TabSubmit, + TabContext ) from botframework.connector import Channels from simple_adapter import SimpleAdapter @@ -294,6 +297,22 @@ async def on_teams_task_module_submit( # pylint: disable=unused-argument turn_context, task_module_request ) + async def on_teams_tab_fetch( + self, turn_context: TurnContext, tab_request: TabRequest + ): + self.record.append("on_teams_tab_fetch") + return await super().on_teams_tab_fetch( + turn_context, tab_request + ) + + async def on_teams_tab_submit( + self, turn_context: TurnContext, tab_submit: TabSubmit + ): + self.record.append("on_teams_tab_submit") + return await super().on_teams_tab_submit( + turn_context, tab_submit + ) + class NotImplementedAdapter(BotAdapter): async def delete_activity( @@ -988,6 +1007,50 @@ async def test_on_teams_task_module_submit(self): assert bot.record[0] == "on_invoke_activity" assert bot.record[1] == "on_teams_task_module_submit" + async def test_on_teams_tab_fetch(self): + # Arrange + activity = Activity( + type=ActivityTypes.invoke, + name="tab/fetch", + value={ + "data": {"key": "value"}, + "context": TabContext().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_tab_fetch" + + async def test_on_teams_tab_submit(self): + # Arrange + activity = Activity( + type=ActivityTypes.invoke, + name="tab/submit", + value={ + "data": {"key": "value"}, + "context": TabContext().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_tab_submit" + async def test_on_end_of_conversation_activity(self): activity = Activity(type=ActivityTypes.end_of_conversation) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 2fe146de6..1f50b862f 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -2296,7 +2296,7 @@ class TabSubmit(Model): } def __init__( - self, *, tab_entity_context=None, context=None, data=data, **kwargs + self, *, tab_entity_context=None, context=None, data=None, **kwargs ) -> None: super(TabSubmit, self).__init__(**kwargs) self.tab_entity_context = tab_entity_context From d5a41a3fd5a498a980efa42fa3a1cb1ba97a8925 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Tue, 2 Feb 2021 15:09:26 -0800 Subject: [PATCH 4/8] fixing formatting --- .../core/teams/teams_activity_handler.py | 10 +++------- .../teams/test_teams_activity_handler.py | 20 +++++-------------- 2 files changed, 8 insertions(+), 22 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 19d5de29b..ced6dd415 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -24,7 +24,7 @@ TaskModuleRequest, TaskModuleResponse, TabRequest, - TabSubmit + TabSubmit, ) from botframework.connector import Channels from ..serializer_helper import deserializer_helper @@ -169,9 +169,7 @@ async def on_invoke_activity(self, turn_context: TurnContext) -> InvokeResponse: return self._create_invoke_response( await self.on_teams_tab_fetch( turn_context, - deserializer_helper( - TabRequest, turn_context.activity.value - ), + deserializer_helper(TabRequest, turn_context.activity.value), ) ) @@ -179,9 +177,7 @@ async def on_invoke_activity(self, turn_context: TurnContext) -> InvokeResponse: return self._create_invoke_response( await self.on_teams_tab_submit( turn_context, - deserializer_helper( - TabSubmit, turn_context.activity.value - ), + deserializer_helper(TabSubmit, turn_context.activity.value), ) ) 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 b532a8989..fad04bb86 100644 --- a/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py +++ b/libraries/botbuilder-core/tests/teams/test_teams_activity_handler.py @@ -29,7 +29,7 @@ TeamsChannelAccount, TabRequest, TabSubmit, - TabContext + TabContext, ) from botframework.connector import Channels from simple_adapter import SimpleAdapter @@ -301,17 +301,13 @@ async def on_teams_tab_fetch( self, turn_context: TurnContext, tab_request: TabRequest ): self.record.append("on_teams_tab_fetch") - return await super().on_teams_tab_fetch( - turn_context, tab_request - ) + return await super().on_teams_tab_fetch(turn_context, tab_request) async def on_teams_tab_submit( self, turn_context: TurnContext, tab_submit: TabSubmit ): self.record.append("on_teams_tab_submit") - return await super().on_teams_tab_submit( - turn_context, tab_submit - ) + return await super().on_teams_tab_submit(turn_context, tab_submit) class NotImplementedAdapter(BotAdapter): @@ -1012,10 +1008,7 @@ async def test_on_teams_tab_fetch(self): activity = Activity( type=ActivityTypes.invoke, name="tab/fetch", - value={ - "data": {"key": "value"}, - "context": TabContext().serialize(), - }, + value={"data": {"key": "value"}, "context": TabContext().serialize(),}, ) turn_context = TurnContext(SimpleAdapter(), activity) @@ -1034,10 +1027,7 @@ async def test_on_teams_tab_submit(self): activity = Activity( type=ActivityTypes.invoke, name="tab/submit", - value={ - "data": {"key": "value"}, - "context": TabContext().serialize(), - }, + value={"data": {"key": "value"}, "context": TabContext().serialize(),}, ) turn_context = TurnContext(SimpleAdapter(), activity) From f3cc169de9201763847069958231859b72310610 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Tue, 2 Feb 2021 15:53:37 -0800 Subject: [PATCH 5/8] Fixed returning Not Implemented on base methods --- .../core/teams/teams_activity_handler.py | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 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 ced6dd415..8163a62ae 100644 --- a/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py +++ b/libraries/botbuilder-core/botbuilder/core/teams/teams_activity_handler.py @@ -484,6 +484,32 @@ async def on_teams_task_module_submit( # pylint: disable=unused-argument """ raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) + async def on_teams_tab_fetch( # pylint: disable=unused-argument + self, turn_context: TurnContext, tab_request: TabRequest + ): + """ + Override this in a derived class to provide logic for when a tab is fetched. + + :param turn_context: A context object for this turn. + :param tab_request: The tab invoke request value payload. + + :returns: A Tab Response for the request. + """ + raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) + + async def on_teams_tab_submit( # pylint: disable=unused-argument + self, turn_context: TurnContext, tab_submit: TabSubmit + ): + """ + Override this in a derived class to provide logic for when a tab is submitted. + + :param turn_context: A context object for this turn. + :param tab_submit: The tab submit invoke request value payload. + + :returns: A Tab Response for the request. + """ + raise _InvokeResponseException(status_code=HTTPStatus.NOT_IMPLEMENTED) + async def on_conversation_update_activity(self, turn_context: TurnContext): """ Invoked when a conversation update activity is received from the channel. @@ -853,29 +879,3 @@ async def on_teams_channel_restored( # pylint: disable=unused-argument :returns: A task that represents the work queued to execute. """ return - - async def on_teams_tab_fetch( # pylint: disable=unused-argument - self, turn_context: TurnContext, tab_request: TabRequest - ): - """ - Override this in a derived class to provide logic for when a tab is fetched. - - :param turn_context: A context object for this turn. - :param tab_request: The tab invoke request value payload. - - :returns: A Tab Response for the request. - """ - return - - async def on_teams_tab_submit( # pylint: disable=unused-argument - self, turn_context: TurnContext, tab_submit: TabSubmit - ): - """ - Override this in a derived class to provide logic for when a tab is submitted. - - :param turn_context: A context object for this turn. - :param tab_submit: The tab submit invoke request value payload. - - :returns: A Tab Response for the request. - """ - return From 216b026a837ec359ed315ed7f1c7e2462c285534 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Tue, 2 Feb 2021 16:01:47 -0800 Subject: [PATCH 6/8] Fix for TabRequest serializer --- .../botbuilder-schema/botbuilder/schema/teams/_models_py3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 1f50b862f..11ac66624 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -2124,7 +2124,7 @@ class TabRequest(Model): """ _attribute_map = { - "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "tab_entity_context": {"key": "tabContext", "type": "TabEntityContext"}, "context": {"key": "context", "type": "TabContext"}, "state": {"key": "state", "type": "str"}, } From d8f1581b041a43be06e9e679bf2b90ec6b167b91 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Fri, 5 Feb 2021 17:43:04 -0800 Subject: [PATCH 7/8] Fixed suggestions on teams schema --- .../botbuilder/schema/teams/_models_py3.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index 11ac66624..d47c68541 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -2168,11 +2168,12 @@ class TabResponseCards(Model): Envelope for cards for a TabResponse. :param cards: Gets or sets adaptive card for this card tab response. - :type cards: list[object] + :type cards: + list[ ~botframework.connector.teams.models.TabResponseCard] """ _attribute_map = { - "cards": {"key": "cards", "type": "[object]"}, + "cards": {"key": "cards", "type": "[TabResponseCard]"}, } def __init__(self, *, cards=None, **kwargs) -> None: @@ -2233,7 +2234,7 @@ class TabSumit(Model): """ _attribute_map = { - "tab_entity_context": {"key": "tabEntityContext", "type": "TabEntityContext"}, + "tab_entity_context": {"key": "tabContext", "type": "TabEntityContext"}, "context": {"key": "context", "type": "TabContext"}, "data": {"key": "data", "type": "TabSubmitData"}, } From 09979dd7f2619068b19d028b60f08770fb0a8df9 Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Fri, 5 Feb 2021 18:05:18 -0800 Subject: [PATCH 8/8] fixed serialization for TabSubmitData --- .../botbuilder-schema/botbuilder/schema/teams/_models_py3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py index d47c68541..71ff05813 100644 --- a/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py +++ b/libraries/botbuilder-schema/botbuilder/schema/teams/_models_py3.py @@ -2265,7 +2265,7 @@ class TabSubmitData(Model): _attribute_map = { "type": {"key": "type", "type": "str"}, - "properties": {"key": "properties", "type": "object"}, + "properties": {"key": "properties", "type": "{object}"}, } def __init__(self, *, type=None, properties=None, **kwargs) -> None: