async def callback(context: TurnContext): context.turn_state[ SkillHandler.SKILL_CONVERSATION_REFERENCE_KEY ] = skill_conversation_reference TurnContext.apply_conversation_reference( activity, skill_conversation_reference.conversation_reference ) context.activity.id = reply_to_activity_id app_id = JwtTokenValidation.get_app_id_from_claims(claims_identity.claims) context.activity.caller_id = ( f"{CallerIdConstants.bot_to_bot_prefix}{app_id}" ) if activity.type == ActivityTypes.end_of_conversation: await self._conversation_id_factory.delete_conversation_reference( conversation_id ) self._apply_eoc_to_turn_context_activity(context, activity) await self._bot.on_turn(context) elif activity.type == ActivityTypes.event: self._apply_event_to_turn_context_activity(context, activity) await self._bot.on_turn(context) else: await context.send_activity(activity)
async def end_dialog( self, context: TurnContext, instance: DialogInstance, reason: DialogReason ): # Send of of conversation to the skill if the dialog has been cancelled. if reason in (DialogReason.CancelCalled, DialogReason.ReplaceCalled): await context.send_trace_activity( f"{SkillDialog.__name__}.end_dialog()", label=f"ActivityType: {context.activity.type}", ) activity = Activity(type=ActivityTypes.end_of_conversation) # Apply conversation reference and common properties from incoming activity before sending. TurnContext.apply_conversation_reference( activity, TurnContext.get_conversation_reference(context.activity), is_incoming=True, ) activity.channel_data = context.activity.channel_data activity.additional_properties = context.activity.additional_properties # connection Name is not applicable for an EndDialog, as we don't expect as OAuthCard in response. skill_conversation_id = instance.state[ SkillDialog.SKILLCONVERSATIONIDSTATEKEY ] await self._send_to_skill(context, activity, skill_conversation_id) await super().end_dialog(context, instance, reason)
async def callback(context: TurnContext): nonlocal resource_response context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = skill_conversation_reference TurnContext.apply_conversation_reference( activity, skill_conversation_reference.conversation_reference) context.activity.id = reply_to_activity_id app_id = JwtTokenValidation.get_app_id_from_claims( claims_identity.claims) context.activity.caller_id = ( f"{CallerIdConstants.bot_to_bot_prefix}{app_id}") if activity.type == ActivityTypes.end_of_conversation: await self._conversation_id_factory.delete_conversation_reference( conversation_id) await self._send_to_bot(activity, context) elif activity.type == ActivityTypes.event: await self._send_to_bot(activity, context) elif activity.type in (ActivityTypes.command, ActivityTypes.command_result): if activity.name.startswith("application/"): # Send to channel and capture the resource response for the SendActivityCall so we can return it. resource_response = await context.send_activity(activity) else: await self._send_to_bot(activity, context) else: # Capture the resource response for the SendActivityCall so we can return it. resource_response = await context.send_activity(activity)
async def test_on_reply_to_activity(self): self._conversation_id = await self._test_id_factory.create_skill_conversation_id( self._conversation_reference) mock_adapter = Mock() mock_adapter.continue_conversation = MagicMock(return_value=Future()) mock_adapter.continue_conversation.return_value.set_result(Mock()) mock_adapter.send_activities = MagicMock(return_value=Future()) mock_adapter.send_activities.return_value.set_result([]) sut = self.create_skill_handler_for_testing(mock_adapter) activity = Activity(type=ActivityTypes.message, attachments=[], entities=[]) activity_id = str(uuid4()) TurnContext.apply_conversation_reference(activity, self._conversation_reference) await sut.test_on_reply_to_activity(self._claims_identity, self._conversation_id, activity_id, activity) args, kwargs = mock_adapter.continue_conversation.call_args_list[0] assert isinstance(args[0], ConversationReference) assert callable(args[1]) assert isinstance(kwargs["claims_identity"], ClaimsIdentity) await args[1](TurnContext( mock_adapter, conversation_reference_extension.get_continuation_activity( self._conversation_reference), )) assert activity.caller_id is None
async def test_forwarding_on_send_to_conversation(self): self._conversation_id = await self._test_id_factory.create_skill_conversation_id( self._conversation_reference) resource_response_id = "rId" async def side_effect(*arg_list, **args_dict): # pylint: disable=unused-argument fake_context = Mock() fake_context.turn_state = {} fake_context.send_activity = MagicMock(return_value=Future()) fake_context.send_activity.return_value.set_result( ResourceResponse(id=resource_response_id)) await arg_list[1](fake_context) mock_adapter = Mock() mock_adapter.continue_conversation = side_effect mock_adapter.send_activities = MagicMock(return_value=Future()) mock_adapter.send_activities.return_value.set_result([]) sut = self.create_skill_handler_for_testing(mock_adapter) activity = Activity(type=ActivityTypes.message, attachments=[], entities=[]) TurnContext.apply_conversation_reference(activity, self._conversation_reference) assert not activity.caller_id response = await sut.test_on_send_to_conversation( self._claims_identity, self._conversation_id, activity) assert response.id is resource_response_id
async def __activity_callback_test(self, activity: Activity): self._conversation_id = await self._test_id_factory.create_skill_conversation_id( self._conversation_reference) mock_adapter = Mock() mock_adapter.continue_conversation = MagicMock(return_value=Future()) mock_adapter.continue_conversation.return_value.set_result(Mock()) mock_adapter.send_activities = MagicMock(return_value=Future()) mock_adapter.send_activities.return_value.set_result([]) sut = self.create_skill_handler_for_testing(mock_adapter) activity_id = str(uuid4()) TurnContext.apply_conversation_reference(activity, self._conversation_reference) await sut.test_on_reply_to_activity(self._claims_identity, self._conversation_id, activity_id, activity) args, kwargs = mock_adapter.continue_conversation.call_args_list[0] assert isinstance(args[0], ConversationReference) assert callable(args[1]) assert isinstance(kwargs["claims_identity"], ClaimsIdentity) await args[1](TurnContext(mock_adapter, activity))
async def send(self, activity: Activity) -> Any: TurnContext.apply_conversation_reference(activity, self._conversation_reference) try: await self._connector_client.conversations.send_to_conversation( activity.conversation.id, activity ) except Exception: return False return True
async def reprompt_dialog( # pylint: disable=unused-argument self, context: TurnContext, instance: DialogInstance): # Create and send an event to the skill so it can resume the dialog. reprompt_event = Activity(type=ActivityTypes.event, name=DialogEvents.reprompt_dialog) # Apply conversation reference and common properties from incoming activity before sending. TurnContext.apply_conversation_reference( reprompt_event, TurnContext.get_conversation_reference(context.activity), is_incoming=True, ) await self._send_to_skill(context, reprompt_event)
async def _send_proactive_threaded_message(self, turn_context: TurnContext): activity = MessageFactory.text( "I will send two messages to this thread") result = await turn_context.send_activity(activity) team_id = TeamsInfo.get_team_id(turn_context) for i in range(2): proactive_activity = MessageFactory.text( f"This is message {i+1}/2 that will be sent.") TurnContext.apply_conversation_reference( proactive_activity, TurnContext.get_conversation_reference(activity)) await turn_context.send_activity(proactive_activity)
async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. # NOTE: In production environment, you should consider logging this to Azure # application insights. print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr) traceback.print_exc() # Send a message to the user await context.send_activity("The bot encountered an error or bug.") await context.send_activity( "To continue to run this bot, please fix the bot source code.") # Send a trace activity if we're talking to the Bot Framework Emulator if context.activity.channel_id == "emulator": # Create a trace activity that contains the error object trace_activity = Activity( label="TurnError", name="on_turn_error Trace", timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", value_type="https://www.botframework.com/schemas/error", ) await context.send_activity(trace_activity) # Inform the active skill that the conversation is ended so that it has # a chance to clean up. # Note: ActiveSkillPropertyName is set by the RooBot while messages are being # forwarded to a Skill. active_skill_id = await CONVERSATION_STATE.create_property( "activeSkillProperty").get(context) if active_skill_id: end_of_conversation = Activity(type=ActivityTypes.end_of_conversation, code="RootSkillError") TurnContext.apply_conversation_reference( end_of_conversation, TurnContext.get_conversation_reference(context.activity), is_incoming=True) await CONVERSATION_STATE.save_changes(context, True) await CLIENT.post_activity( CONFIG.APP_ID, SKILL_CONFIG.SKILLS[active_skill_id], SKILL_CONFIG.SKILL_HOST_ENDPOINT, end_of_conversation, ) # Clear out state await CONVERSATION_STATE.delete(context)
async def continue_conversation( self, reference: ConversationReference, callback: Callable, bot_id: str = None, claims_identity: ClaimsIdentity = None, audience: str = None, ): """ Sends a proactive message to a conversation. Call this method to proactively send a message to a conversation. Most _channels require a user to initiate a conversation with a bot before the bot can send activities to the user. :param bot_id: The application ID of the bot. This parameter is ignored in single tenant the Adpters (Console, Test, etc) but is critical to the BotFrameworkAdapter which is multi-tenant aware. </param> :param reference: A reference to the conversation to continue.</param> :param callback: The method to call for the resulting bot turn.</param> :param claims_identity: """ if not reference: raise Exception("ConversationReference is required") if not callback: raise Exception("callback is required") request = TurnContext.apply_conversation_reference( conversation_reference_extension.get_continuation_activity( reference), reference, ) context = TurnContext(self, request) return await self.run_pipeline(context, callback)
async def test_should_migrate_tenant_id_for_msteams(self): incoming = TurnContext.apply_conversation_reference( activity=Activity( type=ActivityTypes.message, text="foo", channel_data={"tenant": { "id": "1234" }}, ), reference=REFERENCE, is_incoming=True, ) incoming.channel_id = "msteams" adapter = AdapterUnderTest() async def aux_func_assert_tenant_id_copied(context): self.assertEqual( context.activity.conversation.tenant_id, "1234", "should have copied tenant id from " "channel_data to conversation address", ) await adapter.process_activity(incoming, "", aux_func_assert_tenant_id_copied)
async def reprompt_dialog( # pylint: disable=unused-argument self, context: TurnContext, instance: DialogInstance ): # Create and send an event to the skill so it can resume the dialog. reprompt_event = Activity( type=ActivityTypes.event, name=DialogEvents.reprompt_dialog ) # Apply conversation reference and common properties from incoming activity before sending. TurnContext.apply_conversation_reference( reprompt_event, TurnContext.get_conversation_reference(context.activity), is_incoming=True, ) # connection Name is not applicable for a RePrompt, as we don't expect as OAuthCard in response. skill_conversation_id = instance.state[SkillDialog.SKILLCONVERSATIONIDSTATEKEY] await self._send_to_skill(context, reprompt_event, skill_conversation_id)
async def callback(context: TurnContext): context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = skill_conversation_reference TurnContext.apply_conversation_reference(activity, conversation_reference) context.activity.id = reply_to_activity_id if activity.type == ActivityTypes.end_of_conversation: await self._conversation_id_factory.delete_conversation_reference( conversation_id) self._apply_eoc_to_turn_context_activity(context, activity) await self._bot.on_turn(context) elif activity.type == ActivityTypes.event: self._apply_event_to_turn_context_activity(context, activity) await self._bot.on_turn(context) else: await context.send_activity(activity)
async def begin_dialog(self, dialog_context: DialogContext, options: object = None): """ Method called when a new dialog has been pushed onto the stack and is being activated. :param dialog_context: The dialog context for the current turn of conversation. :param options: (Optional) additional argument(s) to pass to the dialog being started. """ dialog_args = self._validate_begin_dialog_args(options) await dialog_context.context.send_trace_activity( f"{SkillDialog.__name__}.BeginDialogAsync()", label=f"Using activity of type: {dialog_args.activity.type}", ) # Create deep clone of the original activity to avoid altering it before forwarding it. skill_activity: Activity = deepcopy(dialog_args.activity) # Apply conversation reference and common properties from incoming activity before sending. TurnContext.apply_conversation_reference( skill_activity, TurnContext.get_conversation_reference(dialog_context.context.activity), is_incoming=True, ) # Store delivery mode in dialog state for later use. dialog_context.active_dialog.state[ self._deliver_mode_state_key ] = dialog_args.activity.delivery_mode # Create the conversationId and store it in the dialog context state so we can use it later skill_conversation_id = await self._create_skill_conversation_id( dialog_context.context, dialog_context.context.activity ) dialog_context.active_dialog.state[ SkillDialog.SKILLCONVERSATIONIDSTATEKEY ] = skill_conversation_id # Send the activity to the skill. eoc_activity = await self._send_to_skill( dialog_context.context, skill_activity, skill_conversation_id ) if eoc_activity: return await dialog_context.end_dialog(eoc_activity.value) return self.end_of_turn
def test_apply_conversation_reference_when_is_incoming_is_true_should_not_prepare_a_reply( self): reference = TurnContext.get_conversation_reference(ACTIVITY) reply = TurnContext.apply_conversation_reference( Activity(type="message", text="reply"), reference, True) assert reply.recipient == ACTIVITY.recipient assert reply.from_property == ACTIVITY.from_property assert reply.conversation == ACTIVITY.conversation assert reply.service_url == ACTIVITY.service_url assert reply.channel_id == ACTIVITY.channel_id
def test_apply_conversation_reference_should_return_prepare_reply_when_is_incoming_is_False( self): reference = TurnContext.get_conversation_reference(ACTIVITY) reply = TurnContext.apply_conversation_reference( Activity(type='message', text='reply'), reference) assert reply.recipient == ACTIVITY.from_property assert reply.from_property == ACTIVITY.recipient assert reply.conversation == ACTIVITY.conversation assert reply.service_url == ACTIVITY.service_url assert reply.channel_id == ACTIVITY.channel_id
async def _end_skill_conversation( self, turn_context: TurnContext, error: Exception # pylint: disable=unused-argument ): if not self._skill_client or not self._skill_config: return try: # Inform the active skill that the conversation is ended so that it has a chance to clean up. # Note: the root bot manages the ActiveSkillPropertyName, which has a value while the root bot # has an active conversation with a skill. active_skill = await self._conversation_state.create_property( MainDialog.ACTIVE_SKILL_PROPERTY_NAME).get(turn_context) if active_skill: bot_id = self._config.APP_ID end_of_conversation = Activity( type=ActivityTypes.end_of_conversation) end_of_conversation.code = "RootSkillError" TurnContext.apply_conversation_reference( end_of_conversation, TurnContext.get_conversation_reference( turn_context.activity), True, ) await self._conversation_state.save_changes(turn_context, True) await self._skill_client.post_activity_to_skill( bot_id, active_skill, self._skill_config.SKILL_HOST_ENDPOINT, end_of_conversation, ) except Exception as exception: print( f"\n Exception caught on _end_skill_conversation : {exception}", file=sys.stderr, ) traceback.print_exc()
async def on_message_activity(self, turn_context: TurnContext): await turn_context.send_activity("parent: before child") activity = MessageFactory.text("parent to child") TurnContext.apply_conversation_reference( activity, TurnContext.get_conversation_reference(turn_context.activity)) activity.delivery_mode = DeliveryModes.expect_replies activities = await self.client.post_buffered_activity( None, "toBotId", "http://localhost:3979/api/messages", "http://tempuri.org/whatever", str(uuid.uuid4()), activity, ) if activities: await turn_context.send_activities(activities) await turn_context.send_activity("parent: after child")
async def end_dialog(self, context: TurnContext, instance: DialogInstance, reason: DialogReason): # Send of of conversation to the skill if the dialog has been cancelled. if reason in (DialogReason.CancelCalled, DialogReason.ReplaceCalled): await context.send_trace_activity( f"{SkillDialog.__name__}.end_dialog()", label=f"ActivityType: {context.activity.type}", ) activity = Activity(type=ActivityTypes.end_of_conversation) # Apply conversation reference and common properties from incoming activity before sending. TurnContext.apply_conversation_reference( activity, TurnContext.get_conversation_reference(context.activity), is_incoming=True, ) activity.channel_data = context.activity.channel_data activity.additional_properties = context.activity.additional_properties await self._send_to_skill(context, activity) await super().end_dialog(context, instance, reason)
async def continue_conversation( self, reference: ConversationReference, callback: Callable, bot_id: str = None, # pylint: disable=unused-argument claims_identity: ClaimsIdentity = None, audience: str = None, # pylint: disable=unused-argument ): """ Send a proactive message to a conversation. .. remarks:: Most channels require a user to initiate a conversation with a bot before the bot can send activities to the user. :param reference: A reference to the conversation to continue. :type reference: :class:`botbuilder.schema.ConversationReference` :param callback: The method to call for the resulting bot turn. :type callback: :class:`typing.Callable` :param bot_id: Unused for this override. :type bot_id: str :param claims_identity: A ClaimsIdentity for the conversation. :type claims_identity: :class:`botframework.connector.auth.ClaimsIdentity` :param audience: Unused for this override. :type audience: str """ if not reference: raise Exception("ConversationReference is required") if not callback: raise Exception("callback is required") if claims_identity: request = conversation_reference_extension.get_continuation_activity( reference) context = TurnContext(self, request) context.turn_state[BotAdapter.BOT_IDENTITY_KEY] = claims_identity context.turn_state[BotAdapter.BOT_CALLBACK_HANDLER_KEY] = callback else: request = TurnContext.apply_conversation_reference( conversation_reference_extension.get_continuation_activity( reference), reference, ) context = TurnContext(self, request) return await self.run_pipeline(context, callback)
async def test_should_migrate_tenant_id_for_msteams(self): incoming = TurnContext.apply_conversation_reference( activity=Activity(type=ActivityTypes.message, text='foo', channel_data={'tenant': { 'id': '1234' }}), reference=reference, is_incoming=True) incoming.channel_id = 'msteams' adapter = AdapterUnderTest() async def aux_func_assert_tenant_id_copied(context): self.assertEquals( context.activity.conversation.tenant_id, '1234', 'should have copied tenant id from ' 'channel_data to conversation address') await adapter.process_activity(incoming, '', aux_func_assert_tenant_id_copied)
async def continue_conversation( self, reference: ConversationReference, callback: Callable, bot_id: str = None, claims_identity: ClaimsIdentity = None, audience: str = None, ): """ Sends a proactive message to a conversation. Call this method to proactively send a message to a conversation. Most _channels require a user to initiate a conversation with a bot before the bot can send activities to the user. :param bot_id: Unused for this override. :param reference: A reference to the conversation to continue. :param callback: The method to call for the resulting bot turn. :param claims_identity: A ClaimsIdentity for the conversation. :param audience: Unused for this override. """ if not reference: raise Exception("ConversationReference is required") if not callback: raise Exception("callback is required") if claims_identity: request = conversation_reference_extension.get_continuation_activity( reference ) context = TurnContext(self, request) context.turn_state[BotAdapter.BOT_IDENTITY_KEY] = claims_identity context.turn_state[BotAdapter.BOT_CALLBACK_HANDLER_KEY] = callback else: request = TurnContext.apply_conversation_reference( conversation_reference_extension.get_continuation_activity(reference), reference, ) context = TurnContext(self, request) return await self.run_pipeline(context, callback)
) REFERENCE = ConversationReference( activity_id="1234", channel_id="test", locale="en-uS", # Intentionally oddly-cased to check that it isn't defaulted somewhere, but tests stay in English service_url="https://example.org/channel", user=ChannelAccount(id="user", name="User Name"), bot=ChannelAccount(id="bot", name="Bot Name"), conversation=ConversationAccount(id="convo1"), ) TEST_ACTIVITY = Activity(text="test", type=ActivityTypes.message) INCOMING_MESSAGE = TurnContext.apply_conversation_reference( copy(TEST_ACTIVITY), REFERENCE, True ) OUTGOING_MESSAGE = TurnContext.apply_conversation_reference( copy(TEST_ACTIVITY), REFERENCE ) INCOMING_INVOKE = TurnContext.apply_conversation_reference( Activity(type=ActivityTypes.invoke), REFERENCE, True ) class AdapterUnderTest(BotFrameworkAdapter): def __init__(self, settings=None): super().__init__(settings) self.tester = aiounittest.AsyncTestCase() self.fail_auth = False self.fail_operation = False
async def test_on_reply_to_activity(self): resource_response_id = "resourceId" self._conversation_id = await self._test_id_factory.create_skill_conversation_id( self._conversation_reference) types_to_test = [ ActivityTypes.end_of_conversation, ActivityTypes.event, ActivityTypes.message, ] for activity_type in types_to_test: with self.subTest(act_type=activity_type): mock_adapter = Mock() mock_adapter.continue_conversation = MagicMock( return_value=Future()) mock_adapter.continue_conversation.return_value.set_result( Mock()) mock_adapter.send_activities = MagicMock(return_value=Future()) mock_adapter.send_activities.return_value.set_result( [ResourceResponse(id=resource_response_id)]) sut = self.create_skill_handler_for_testing(mock_adapter) activity = Activity(type=activity_type, attachments=[], entities=[]) activity_id = str(uuid4()) TurnContext.apply_conversation_reference( activity, self._conversation_reference) resource_response = await sut.test_on_reply_to_activity( self._claims_identity, self._conversation_id, activity_id, activity) # continue_conversation validation ( args_continue, kwargs_continue, ) = mock_adapter.continue_conversation.call_args_list[0] mock_adapter.continue_conversation.assert_called_once() assert isinstance(args_continue[0], ConversationReference) assert callable(args_continue[1]) assert isinstance(kwargs_continue["claims_identity"], ClaimsIdentity) turn_context = TurnContext( mock_adapter, conversation_reference_extension.get_continuation_activity( self._conversation_reference), ) await args_continue[1](turn_context) # assert the callback set the right properties. assert (f"{CallerIdConstants.bot_to_bot_prefix}{self.skill_id}" ), turn_context.activity.caller_id if activity_type == ActivityTypes.message: # send_activities validation ( args_send, _, ) = mock_adapter.send_activities.call_args_list[0] activity_from_send = args_send[1][0] assert activity_from_send.caller_id is None assert activity_from_send.reply_to_id, activity_id assert resource_response.id, resource_response_id else: # Assert mock SendActivitiesAsync wasn't called mock_adapter.send_activities.assert_not_called()
async def test_on_send_to_conversation(self): self._conversation_id = await self._test_id_factory.create_skill_conversation_id( self._conversation_reference) # python 3.7 doesn't support AsyncMock, change this when min ver is 3.8 send_activities_called = False mock_adapter = Mock() async def continue_conversation( reference: ConversationReference, callback: Callable, bot_id: str = None, claims_identity: ClaimsIdentity = None, audience: str = None, ): # pylint: disable=unused-argument # Invoke the callback created by the handler so we can assert the rest of the execution. turn_context = TurnContext( mock_adapter, conversation_reference_extension.get_continuation_activity( self._conversation_reference), ) await callback(turn_context) # Assert the callback set the right properties. assert (f"{CallerIdConstants.bot_to_bot_prefix}{self.skill_id}" ), turn_context.activity.caller_id async def send_activities(context: TurnContext, activities: List[Activity]): # pylint: disable=unused-argument # Messages should not have a caller id set when sent back to the caller. nonlocal send_activities_called assert activities[0].caller_id is None assert activities[0].reply_to_id is None send_activities_called = True return [ResourceResponse(id="resourceId")] mock_adapter.continue_conversation = continue_conversation mock_adapter.send_activities = send_activities types_to_test = [ ActivityTypes.end_of_conversation, ActivityTypes.event, ActivityTypes.message, ] for activity_type in types_to_test: with self.subTest(act_type=activity_type): send_activities_called = False activity = Activity(type=activity_type, attachments=[], entities=[]) TurnContext.apply_conversation_reference( activity, self._conversation_reference) sut = self.create_skill_handler_for_testing(mock_adapter) resource_response = await sut.test_on_send_to_conversation( self._claims_identity, self._conversation_id, activity) if activity_type == ActivityTypes.message: assert send_activities_called assert resource_response.id == "resourceId"
from botbuilder.core import BotFrameworkAdapter, BotFrameworkAdapterSettings, TurnContext from botbuilder.schema import Activity, ActivityTypes, ConversationAccount, ConversationReference, ChannelAccount from botframework.connector.aio import ConnectorClient from botframework.connector.auth import ClaimsIdentity reference = ConversationReference( activity_id='1234', channel_id='test', service_url='https://example.org/channel', user=ChannelAccount(id='user', name='User Name'), bot=ChannelAccount(id='bot', name='Bot Name'), conversation=ConversationAccount(id='convo1')) test_activity = Activity(text='test', type=ActivityTypes.message) incoming_message = TurnContext.apply_conversation_reference( copy(test_activity), reference, True) outgoing_message = TurnContext.apply_conversation_reference( copy(test_activity), reference) incoming_invoke = TurnContext.apply_conversation_reference( Activity(type=ActivityTypes.invoke), reference, True) class AdapterUnderTest(BotFrameworkAdapter): def __init__(self, settings=None): super().__init__(settings) self.tester = aiounittest.AsyncTestCase() self.fail_auth = False self.fail_operation = False self.expect_auth_header = '' self.new_service_url = None
async def on_message_activity(self, turn_context: TurnContext): # for signin, just use an oauth prompt to get the exchangeable token # also ensure that the channelId is not emulator if turn_context.activity.type != "emulator": if (turn_context.activity.text == "login" or turn_context.activity.text.isdigit()): await self._conversation_state.load(turn_context, True) await self._user_state.load(turn_context, True) await DialogHelper.run_dialog( self._dialog, turn_context, self._conversation_state.create_property("DialogState"), ) elif turn_context.activity.text == "logout": bot_adapter = turn_context.adapter await bot_adapter.sign_out_user(turn_context, self._connection_name) await turn_context.send_activity( MessageFactory.text("You have been signed out.")) elif turn_context.activity.text in ("skill login", "skill logout"): # incoming activity needs to be cloned for buffered replies clone_activity = MessageFactory.text( turn_context.activity.text) TurnContext.apply_conversation_reference( clone_activity, TurnContext.get_conversation_reference( turn_context.activity), True, ) clone_activity.delivery_mode = DeliveryModes.expect_replies activities = await self._client.post_buffered_activity( self._from_bot_id, self._to_bot_id, "http://localhost:3979/api/messages", "http://tempuri.org/whatever", turn_context.activity.conversation.id, clone_activity, ) if activities: if not await self._intercept_oauth_cards( activities, turn_context): await turn_context.send_activities(activities) return await turn_context.send_activity( MessageFactory.text("parent: before child")) activity = MessageFactory.text("parent: before child") TurnContext.apply_conversation_reference( activity, TurnContext.get_conversation_reference(turn_context.activity), True, ) activity.delivery_mode = DeliveryModes.expect_replies activities = await self._client.post_buffered_activity( self._from_bot_id, self._to_bot_id, "http://localhost:3979/api/messages", "http://tempuri.org/whatever", str(uuid4()), activity, ) await turn_context.send_activities(activities) await turn_context.send_activity( MessageFactory.text("parent: after child"))