Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
O365ConnectorCardActionQuery,
TaskModuleRequest,
TaskModuleResponse,
TabRequest,
TabSubmit,
)
from botframework.connector import Channels
from ..serializer_helper import deserializer_helper
Expand Down Expand Up @@ -163,6 +165,22 @@ 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_tab_fetch(
turn_context,
deserializer_helper(TabRequest, turn_context.activity.value),
)
)

if turn_context.activity.name == "tab/submit":
return self._create_invoke_response(
await self.on_teams_tab_submit(
turn_context,
deserializer_helper(TabSubmit, turn_context.activity.value),
)
)

return await super().on_invoke_activity(turn_context)

except _InvokeResponseException as invoke_exception:
Expand Down Expand Up @@ -466,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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
TaskModuleRequestContext,
TeamInfo,
TeamsChannelAccount,
TabRequest,
TabSubmit,
TabContext,
)
from botframework.connector import Channels
from simple_adapter import SimpleAdapter
Expand Down Expand Up @@ -294,6 +297,18 @@ 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(
Expand Down Expand Up @@ -988,6 +1003,44 @@ 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)

Expand Down
18 changes: 18 additions & 0 deletions libraries/botbuilder-schema/botbuilder/schema/teams/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -125,4 +134,13 @@
"TeamsMeetingParticipant",
"MeetingParticipantInfo",
"CacheInfo",
"TabContext",
"TabRequest",
"TabResponseCard",
"TabResponseCards",
"TabResponsePayload",
"TabSubmit",
"TabSubmitData",
"TabSuggestedActions",
"TaskModuleCardResponse",
]
Loading