|
1 | 1 | # Copyright (c) Microsoft Corporation. All rights reserved.
|
2 | 2 | # Licensed under the MIT License.
|
3 |
| -from typing import List |
4 |
| - |
5 |
| -from botbuilder.schema import ActivityTypes, ChannelAccount, MessageReaction |
| 3 | +from http import HTTPStatus |
| 4 | +from typing import List, Union |
| 5 | + |
| 6 | +from botbuilder.schema import ( |
| 7 | + Activity, |
| 8 | + ActivityTypes, |
| 9 | + ChannelAccount, |
| 10 | + MessageReaction, |
| 11 | + SignInConstants, |
| 12 | +) |
| 13 | +from .serializer_helper import serializer_helper |
| 14 | +from .bot_framework_adapter import BotFrameworkAdapter |
| 15 | +from .invoke_response import InvokeResponse |
6 | 16 | from .turn_context import TurnContext
|
7 | 17 |
|
8 | 18 |
|
@@ -58,6 +68,16 @@ async def on_turn(self, turn_context: TurnContext):
|
58 | 68 | await self.on_message_reaction_activity(turn_context)
|
59 | 69 | elif turn_context.activity.type == ActivityTypes.event:
|
60 | 70 | await self.on_event_activity(turn_context)
|
| 71 | + elif turn_context.activity.type == ActivityTypes.invoke: |
| 72 | + invoke_response = await self.on_invoke_activity(turn_context) |
| 73 | + |
| 74 | + # If OnInvokeActivityAsync has already sent an InvokeResponse, do not send another one. |
| 75 | + if invoke_response and not turn_context.turn_state.get( |
| 76 | + BotFrameworkAdapter._INVOKE_RESPONSE_KEY # pylint: disable=protected-access |
| 77 | + ): |
| 78 | + await turn_context.send_activity( |
| 79 | + Activity(value=invoke_response, type=ActivityTypes.invoke_response) |
| 80 | + ) |
61 | 81 | elif turn_context.activity.type == ActivityTypes.end_of_conversation:
|
62 | 82 | await self.on_end_of_conversation_activity(turn_context)
|
63 | 83 | else:
|
@@ -269,7 +289,7 @@ async def on_event_activity(self, turn_context: TurnContext):
|
269 | 289 | The meaning of an event activity is defined by the event activity name property, which is meaningful within
|
270 | 290 | the scope of a channel.
|
271 | 291 | """
|
272 |
| - if turn_context.activity.name == "tokens/response": |
| 292 | + if turn_context.activity.name == SignInConstants.token_response_event_name: |
273 | 293 | return await self.on_token_response_event(turn_context)
|
274 | 294 |
|
275 | 295 | return await self.on_event(turn_context)
|
@@ -344,3 +364,58 @@ async def on_unrecognized_activity_type( # pylint: disable=unused-argument
|
344 | 364 | conversation update, message reaction, or event activity, it calls this method.
|
345 | 365 | """
|
346 | 366 | return
|
| 367 | + |
| 368 | + async def on_invoke_activity( # pylint: disable=unused-argument |
| 369 | + self, turn_context: TurnContext |
| 370 | + ) -> Union[InvokeResponse, None]: |
| 371 | + """ |
| 372 | + Registers an activity event handler for the _invoke_ event, emitted for every incoming event activity. |
| 373 | +
|
| 374 | + :param turn_context: The context object for this turn |
| 375 | + :type turn_context: :class:`botbuilder.core.TurnContext` |
| 376 | +
|
| 377 | + :returns: A task that represents the work queued to execute |
| 378 | + """ |
| 379 | + try: |
| 380 | + if ( |
| 381 | + turn_context.activity.name |
| 382 | + == SignInConstants.verify_state_operation_name |
| 383 | + or turn_context.activity.name |
| 384 | + == SignInConstants.token_exchange_operation_name |
| 385 | + ): |
| 386 | + await self.on_sign_in_invoke(turn_context) |
| 387 | + return self._create_invoke_response() |
| 388 | + |
| 389 | + raise _InvokeResponseException(HTTPStatus.NOT_IMPLEMENTED) |
| 390 | + except _InvokeResponseException as invoke_exception: |
| 391 | + return invoke_exception.create_invoke_response() |
| 392 | + |
| 393 | + async def on_sign_in_invoke( # pylint: disable=unused-argument |
| 394 | + self, turn_context: TurnContext |
| 395 | + ): |
| 396 | + """ |
| 397 | + Invoked when a signin/verifyState or signin/tokenExchange event is received when the base behavior of |
| 398 | + on_invoke_activity(TurnContext{InvokeActivity}) is used. |
| 399 | + If using an OAuthPrompt, override this method to forward this Activity"/ to the current dialog. |
| 400 | + By default, this method does nothing. |
| 401 | +
|
| 402 | + :param turn_context: The context object for this turn |
| 403 | + :type turn_context: :class:`botbuilder.core.TurnContext` |
| 404 | +
|
| 405 | + :returns: A task that represents the work queued to execute |
| 406 | + """ |
| 407 | + raise _InvokeResponseException(HTTPStatus.NOT_IMPLEMENTED) |
| 408 | + |
| 409 | + @staticmethod |
| 410 | + def _create_invoke_response(body: object = None) -> InvokeResponse: |
| 411 | + return InvokeResponse(status=int(HTTPStatus.OK), body=serializer_helper(body)) |
| 412 | + |
| 413 | + |
| 414 | +class _InvokeResponseException(Exception): |
| 415 | + def __init__(self, status_code: HTTPStatus, body: object = None): |
| 416 | + super(_InvokeResponseException, self).__init__() |
| 417 | + self._status_code = status_code |
| 418 | + self._body = body |
| 419 | + |
| 420 | + def create_invoke_response(self) -> InvokeResponse: |
| 421 | + return InvokeResponse(status=int(self._status_code), body=self._body) |
0 commit comments