async def post_activity( self, from_bot_id: str, to_bot_id: str, to_url: str, service_url: str, conversation_id: str, activity: Activity, ) -> InvokeResponse: app_credentials = await self._get_app_credentials( from_bot_id, to_bot_id) if not app_credentials: raise KeyError( "Unable to get appCredentials to connect to the skill") # Get token for the skill call token = (app_credentials.get_access_token() if app_credentials.microsoft_app_id else None) # Capture current activity settings before changing them. # TODO: DO we need to set the activity ID? (events that are created manually don't have it). original_conversation_id = activity.conversation.id original_service_url = activity.service_url original_caller_id = activity.caller_id try: activity.conversation.id = conversation_id activity.service_url = service_url activity.caller_id = from_bot_id headers_dict = { "Content-type": "application/json; charset=utf-8", } if token: headers_dict.update({ "Authorization": f"Bearer {token}", }) json_content = json.dumps(activity.serialize()) resp = await self._session.post( to_url, data=json_content.encode("utf-8"), headers=headers_dict, ) resp.raise_for_status() data = (await resp.read()).decode() content = json.loads(data) if data else None if content: return InvokeResponse(status=resp.status, body=content) finally: # Restore activity properties. activity.conversation.id = original_conversation_id activity.service_url = original_service_url activity.caller_id = original_caller_id
async def process_activity_with_identity(self, activity: Activity, identity: ClaimsIdentity, logic: Callable): context = self._create_context(activity) context.turn_state[BotAdapter.BOT_IDENTITY_KEY] = identity context.turn_state[BotAdapter.BOT_CALLBACK_HANDLER_KEY] = logic # To create the correct cache key, provide the OAuthScope when calling CreateConnectorClientAsync. # The OAuthScope is also stored on the TurnState to get the correct AppCredentials if fetching a token # is required. scope = (self.__get_botframework_oauth_scope() if not SkillValidation.is_skill_claim(identity.claims) else JwtTokenValidation.get_app_id_from_claims(identity.claims)) context.turn_state[BotAdapter.BOT_OAUTH_SCOPE_KEY] = scope client = await self.create_connector_client(activity.service_url, identity, scope) context.turn_state[BotAdapter.BOT_CONNECTOR_CLIENT_KEY] = client # Fix to assign tenant_id from channelData to Conversation.tenant_id. # MS Teams currently sends the tenant ID in channelData and the correct behavior is to expose # this value in Activity.Conversation.tenant_id. # This code copies the tenant ID from channelData to Activity.Conversation.tenant_id. # Once MS Teams sends the tenant_id in the Conversation property, this code can be removed. if (Channels.ms_teams == context.activity.channel_id and context.activity.conversation is not None and not context.activity.conversation.tenant_id and context.activity.channel_data): teams_channel_data = context.activity.channel_data if teams_channel_data.get("tenant", {}).get("id", None): context.activity.conversation.tenant_id = str( teams_channel_data["tenant"]["id"]) await self.run_pipeline(context, logic) if activity.type == ActivityTypes.invoke: invoke_response = context.turn_state.get( BotFrameworkAdapter._INVOKE_RESPONSE_KEY # pylint: disable=protected-access ) if invoke_response is None: return InvokeResponse(status=501) return invoke_response.value # Return the buffered activities in the response. In this case, the invoker # should deserialize accordingly: # activities = [Activity().deserialize(activity) for activity in response.body] if context.activity.delivery_mode == DeliveryModes.buffered_replies: serialized_activities = [ activity.serialize() for activity in context.buffered_replies ] return InvokeResponse(status=200, body=serialized_activities) return None
async def _post_content( self, to_url: str, token: str, activity: Activity ) -> (int, object): headers_dict = { "Content-type": "application/json; charset=utf-8", } if token: headers_dict.update( {"Authorization": f"Bearer {token}",} ) json_content = json.dumps(activity.serialize()) resp = await self._session.post( to_url, data=json_content.encode("utf-8"), headers=headers_dict, ) resp.raise_for_status() data = (await resp.read()).decode() return resp.status, json.loads(data) if data else None
async def post_activity( self, from_bot_id: str, to_bot_id: str, to_url: str, service_url: str, conversation_id: str, activity: Activity, ) -> InvokeResponse: app_credentials = await self._get_app_credentials( from_bot_id, to_bot_id) if not app_credentials: raise KeyError( "Unable to get appCredentials to connect to the skill") # Get token for the skill call token = (app_credentials.get_access_token() if app_credentials.microsoft_app_id else None) # Capture current activity settings before changing them. # TODO: DO we need to set the activity ID? (events that are created manually don't have it). original_conversation_id = activity.conversation.id original_service_url = activity.service_url original_caller_id = activity.caller_id original_relates_to = activity.relates_to try: # TODO: The relato has to be ported to the adapter in the new integration library when # resolving conflicts in merge activity.relates_to = ConversationReference( service_url=activity.service_url, activity_id=activity.id, channel_id=activity.channel_id, conversation=ConversationAccount( id=activity.conversation.id, name=activity.conversation.name, conversation_type=activity.conversation.conversation_type, aad_object_id=activity.conversation.aad_object_id, is_group=activity.conversation.is_group, role=activity.conversation.role, tenant_id=activity.conversation.tenant_id, properties=activity.conversation.properties, ), bot=None, ) activity.conversation.id = conversation_id activity.service_url = service_url activity.caller_id = f"urn:botframework:aadappid:{from_bot_id}" headers_dict = { "Content-type": "application/json; charset=utf-8", } if token: headers_dict.update({ "Authorization": f"Bearer {token}", }) json_content = json.dumps(activity.serialize()) resp = await self._session.post( to_url, data=json_content.encode("utf-8"), headers=headers_dict, ) resp.raise_for_status() data = (await resp.read()).decode() content = json.loads(data) if data else None return InvokeResponse(status=resp.status, body=content) finally: # Restore activity properties. activity.conversation.id = original_conversation_id activity.service_url = original_service_url activity.caller_id = original_caller_id activity.relates_to = original_relates_to
def _log_activity_as_json(self, actor: str, activity: Activity) -> None: activity_dict = activity.serialize() activity_json = json.dumps(activity_dict, indent=self._json_indent) message = f"{actor}: Activity = {activity.type}\r\n" f"{activity_json}" self._log(message)
async def _fill_out_user_profile( self, flow: ConversationFlow, profile: UserProfile, turn_context: TurnContext ): user_object = dict(eval(json.dumps(Activity.serialize(turn_context.activity)))) self.update_user_login(user_object) user_input = turn_context.activity.text.strip() # ask for name if flow.last_question_asked == Question.NONE: auth_user = self.get_account_by_login(self.user_skype_login) self.update_user_object(auth_user) if not self.user_skype_object: await turn_context.send_activity( MessageFactory.text("We can't identify you. Please contact to support skype") ) else: await turn_context.send_activity( MessageFactory.text(f"Hello, {self.user_skype_object['name']}") ) self.auth = True if self.user_skype_object else False if self.auth: flow.last_question_asked = Question.ALLOCATION # await turn_context.send_activity( # MessageFactory.text(f"Hello") # ) # flow.last_question_asked = Question.ALLOCATION # validate name then ask for age elif flow.last_question_asked == Question.ALLOCATION: validate_result = self._recognize_allocation(user_input) if not validate_result.is_valid: await turn_context.send_activity( MessageFactory.text(validate_result.message) ) else: profile.name = validate_result.value print(profile) await turn_context.send_activity( MessageFactory.text(f"Hi {profile.name}") ) await turn_context.send_activity( MessageFactory.text("How old are you?") ) flow.last_question_asked = Question.NONE # validate age then ask for date elif flow.last_question_asked == Question.AGE: validate_result = self._validate_age(user_input) if not validate_result.is_valid: await turn_context.send_activity( MessageFactory.text(validate_result.message) ) else: profile.age = validate_result.value await turn_context.send_activity( MessageFactory.text(f"I have your age as {profile.age}.") ) await turn_context.send_activity( MessageFactory.text("When is your flight?") ) # flow.last_question_asked = Question.DATE # validate date and wrap it up elif flow.last_question_asked == Question.DATE: validate_result = self._validate_date(user_input) if not validate_result.is_valid: await turn_context.send_activity( MessageFactory.text(validate_result.message) ) else: profile.date = validate_result.value await turn_context.send_activity( MessageFactory.text( f"Your cab ride to the airport is scheduled for {profile.date}." ) ) await turn_context.send_activity( MessageFactory.text( f"Thanks for completing the booking {profile.name}." ) ) await turn_context.send_activity( MessageFactory.text("Type anything to run the bot again.") ) flow.last_question_asked = Question.NONE