예제 #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 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
    async def process_activity(
        self,
        auth_header_or_authenticate_request_result: Union[
            str, AuthenticateRequestResult
        ],
        activity: Activity,
        logic: Callable[[TurnContext], Awaitable],
    ):
        """
        Creates a turn context and runs the middleware pipeline for an incoming activity.

        :param auth_header: The HTTP authentication header of the request
        :type auth_header: :class:`typing.Union[typing.str, AuthenticateRequestResult]`
        :param activity: The incoming activity
        :type activity: :class:`Activity`
        :param logic: The logic to execute at the end of the adapter's middleware pipeline.
        :type logic: :class:`typing.Callable`

        :return: A task that represents the work queued to execute.

        .. remarks::
            This class processes an activity received by the bots web server. This includes any messages
            sent from a user and is the method that drives what's often referred to as the
            bots *reactive messaging* flow.
            Call this method to reactively send a message to a conversation.
            If the task completes successfully, then an :class:`InvokeResponse` is returned;
            otherwise. `null` is returned.
        """
        # Authenticate the inbound request, extracting parameters and create a ConnectorFactory for creating a
        # Connector for outbound requests.
        authenticate_request_result = (
            await self.bot_framework_authentication.authenticate_request(
                activity, auth_header_or_authenticate_request_result
            )
            if isinstance(auth_header_or_authenticate_request_result, str)
            else auth_header_or_authenticate_request_result
        )

        # Set the caller_id on the activity
        activity.caller_id = authenticate_request_result.caller_id

        # Create the connector client to use for outbound requests.
        connector_client = (
            await authenticate_request_result.connector_factory.create(
                activity.service_url, authenticate_request_result.audience
            )
            if authenticate_request_result.connector_factory
            else None
        )

        if not connector_client:
            raise Error("Unable to extract ConnectorClient from turn context.")

        # Create a UserTokenClient instance for the application to use.
        # (For example, it would be used in a sign-in prompt.)
        user_token_client = await self.bot_framework_authentication.create_user_token_client(
            authenticate_request_result.claims_identity
        )

        # Create a turn context and run the pipeline.
        context = self._create_turn_context(
            activity,
            authenticate_request_result.claims_identity,
            authenticate_request_result.audience,
            connector_client,
            user_token_client,
            logic,
            authenticate_request_result.connector_factory,
        )

        # Run the pipeline
        await self.run_pipeline(context, logic)

        # If there are any results they will have been left on the TurnContext.
        return self._process_turn_results(context)