예제 #1
0
    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
예제 #2
0
    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
예제 #4
0
    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
예제 #5
0
 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)
예제 #6
0
    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