Ejemplo n.º 1
0
        public async Task <ConfirmResult> Recognize(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            IMessageActivity message = context.Activity.AsMessageActivity();
            var confirmResult        = new ConfirmResult();
            var results = model.Parse(message.Text);

            if (results.Any())
            {
                var result = results.First();
                if (bool.TryParse(result.Resolution["value"].ToString(), out bool value))
                {
                    confirmResult.Status       = PromptStatus.Recognized;
                    confirmResult.Confirmation = value;
                    confirmResult.Text         = result.Text;
                    if (Validator != null)
                    {
                        await Validator(context, confirmResult);
                    }
                }
            }
            return(confirmResult);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Process the request from WeChat.
        /// </summary>
        /// <param name="wechatRequest">Request message entity from wechat.</param>
        /// <param name="callback"> Bot callback handler.</param>
        /// <param name="cancellationToken">Cancellation Token of this Task.</param>
        /// <returns>Response message entity.</returns>
        private async Task <object> ProcessWeChatRequest(IRequestMessageBase wechatRequest, BotCallbackHandler callback, CancellationToken cancellationToken)
        {
            var activity = await _wechatMessageMapper.ToConnectorMessage(wechatRequest).ConfigureAwait(false);

            BotAssert.ActivityNotNull(activity);
            return(await ProcessActivityAsync(activity, callback, cancellationToken).ConfigureAwait(false));
        }
        /// <summary>
        /// Used to validate the incoming text, expected on context.Activity, is
        /// valid according to the rules defined in the validation steps.
        /// </summary>
        public override async Task <NumberWithUnit> Recognize(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            IMessageActivity message = context.Activity.AsMessageActivity();
            NumberWithUnit   value   = new NumberWithUnit();
            var results = _model.Parse(message.Text);

            if (results.Any())
            {
                var result = results.First();
                value.Unit = (string)result.Resolution["unit"];
                if (float.TryParse(result.Resolution["value"]?.ToString() ?? String.Empty, out float val))
                {
                    value.Status = PromptStatus.Recognized;
                    value.Text   = result.Text;
                    value.Value  = val;
                    await Validate(context, value);
                }
            }
            return(value);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Used to validate the incoming text, expected on context.Request, is
        /// valid according to the rules defined in the validation steps.
        /// </summary>
        public override async Task <ValueResult> Recognize(IBotContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Request);
            if (context.Request.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            IMessageActivity message = context.Request.AsMessageActivity();
            var results = _model.Parse(message.Text);

            if (results.Any())
            {
                var         result = results.First();
                ValueResult value  = new ValueResult()
                {
                    Text  = result.Text,
                    Value = (string)result.Resolution["value"]
                };

                if (await Validate(context, value))
                {
                    return(value);
                }
            }
            return(null);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Prompt the User to signin if not already signed in for the given connection name.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="activity"></param>
        /// <returns></returns>
        public async Task Prompt(ITurnContext context, IMessageActivity activity)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(activity);

            var adapter = context.Adapter as BotFrameworkAdapter;

            if (adapter == null)
            {
                throw new InvalidOperationException("OAuthPrompt.Prompt(): not supported by the current adapter");
            }

            if (activity.Attachments == null || activity.Attachments.Count == 0)
            {
                throw new InvalidOperationException("OAuthPrompt.Prompt(): length of attachments cannot be null");
            }

            var cards = activity.Attachments.Where(a => a.Content is OAuthCard);

            if (cards.Count() == 0)
            {
                throw new InvalidOperationException("OAuthPrompt.Prompt(): at least one of the cards should be an oauth card");
            }

            var replyActivity = MessageFactory.Attachment(cards.First());//todo:send an oauth or signin card based on channel id
            await context.SendActivity(replyActivity).ConfigureAwait(false);
        }
Ejemplo n.º 6
0
        //protected ConfirmPrompt(IModel model, PromptValidator<ConfirmResult> validator = null)
        //    : base(validator)
        //{
        //    this._model = model;
        //}

        public override async Task <ConfirmResult> Recognize(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            IMessageActivity message = context.Activity.AsMessageActivity();
            var   confirmResult      = new ConfirmResult();
            Match yesMatch           = yes.Match(message.Text);
            Match noMatch            = no.Match(message.Text);

            if (yesMatch.Success)
            {
                confirmResult.Status       = PromptStatus.Recognized;
                confirmResult.Confirmation = true;
                confirmResult.Text         = yesMatch.Value;
                await Validate(context, confirmResult);
            }
            else if (noMatch.Success)
            {
                confirmResult.Status       = PromptStatus.Recognized;
                confirmResult.Confirmation = false;
                confirmResult.Text         = noMatch.Value;
                await Validate(context, confirmResult);
            }
            return(confirmResult);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Used to validate the incoming text, expected on context.Request, is
        /// valid according to the rules defined in the validation steps.
        /// </summary>
        /// <param name="context">Context for the current turn of the conversation with the user.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task <DateTimeResult> RecognizeAsync(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type == ActivityTypes.Message)
            {
                var message = context.Activity.AsMessageActivity();
                var results = _model.Parse(message.Text);
                if (results.Any())
                {
                    var values = (List <Dictionary <string, string> >)results[0].Resolution["values"];

                    var dateTimeResult = new DateTimeResult
                    {
                        Status = PromptStatus.Recognized,
                        Text   = message.Text,
                    };

                    foreach (var value in values)
                    {
                        dateTimeResult.Resolution.Add(ReadResolution(value));
                    }

                    await ValidateAsync(context, dateTimeResult).ConfigureAwait(false);

                    return(dateTimeResult);
                }
            }

            return(new DateTimeResult());
        }
Ejemplo n.º 8
0
#pragma warning restore CA2227 // Collection properties should be read only

        /// <summary>
        /// Primary adapter method for processing activities sent from streaming channel.
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// Throws <see cref="ArgumentNullException"/> on null arguments.
        /// </summary>
        /// <param name="activity">The <see cref="Activity"/> to process.</param>
        /// <param name="callbackHandler">The <see cref="BotCallbackHandler"/> that will handle the activity.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// If the task completes successfully, then if the activity's <see cref="Activity.Type"/>
        /// is <see cref="ActivityTypes.Invoke"/> and the corresponding key
        /// (<see cref="Activity.ChannelId"/> + <see cref="Activity.Id"/>) is found
        /// then an <see cref="InvokeResponse"/> is returned, otherwise null is returned.
        /// <para>This method registers the following services for the turn.<list type="bullet"/></para>
        /// </remarks>
        public async Task <InvokeResponse> ProcessStreamingActivityAsync(Activity activity, BotCallbackHandler callbackHandler, CancellationToken cancellationToken = default)
        {
            BotAssert.ActivityNotNull(activity);

            Logger.LogInformation($"Received an incoming streaming activity. ActivityId: {activity.Id}");

            // If a StreamingRequestHandler.Audience is a null value, then no callerId should have been generated
            // and GetAudienceFromCallerId returns null.
            // Thus we fallback to relying on the "original key", essentially $"{ServiceUrl}{Conversation.Id}",
            // as opposed to $"{ServiceUrl}{Audience}{Conversation.Id}" and the StreamingRequestHandler implicitly does not support skills.
            var audience = GetAudienceFromCallerId(activity);

            // If a conversation has moved from one connection to another for the same Channel or Skill and
            // hasn't been forgotten by the previous StreamingRequestHandler. The last requestHandler
            // the conversation has been associated with should always be the active connection.
            var requestHandler = RequestHandlers.Where(
                h => h.ServiceUrl == activity.ServiceUrl &&
                h.Audience == audience &&
                h.HasConversation(activity.Conversation.Id))
                                 .LastOrDefault();

            using (var context = new TurnContext(this, activity))
            {
                context.TurnState.Add <string>(OAuthScopeKey, audience);

                // Pipes are unauthenticated. Pending to check that we are in pipes right now. Do not merge to master without that.
                if (ClaimsIdentity != null)
                {
                    context.TurnState.Add <IIdentity>(BotIdentityKey, ClaimsIdentity);
                }

                using (var connectorClient = CreateStreamingConnectorClient(activity, requestHandler))
                {
                    // Add connector client to be used throughout the turn
                    context.TurnState.Add(connectorClient);

                    await RunPipelineAsync(context, callbackHandler, cancellationToken).ConfigureAwait(false);

                    // Cleanup connector client
                    context.TurnState.Set <IConnectorClient>(null);
                }

                if (activity.Type == ActivityTypes.Invoke)
                {
                    var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeResponseKey);
                    if (activityInvokeResponse == null)
                    {
                        return(new InvokeResponse {
                            Status = (int)HttpStatusCode.NotImplemented
                        });
                    }
                    else
                    {
                        return((InvokeResponse)activityInvokeResponse.Value);
                    }
                }

                return(null);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Used to validate the incoming text, expected on context.Request, is
        /// valid according to the rules defined in the validation steps.
        /// </summary>
        public override async Task <NumberResult <float> > Recognize(IBotContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Request);
            if (context.Request.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            IMessageActivity message = context.Request.AsMessageActivity();
            var results = _model.Parse(message.Text);

            if (results.Any())
            {
                var result = results.First();
                if (float.TryParse(result.Resolution["value"].ToString().TrimEnd('%'), out float value))
                {
                    NumberResult <float> numberResult = new NumberResult <float>()
                    {
                        Value = value,
                        Text  = result.Text
                    };
                    if (await Validate(context, numberResult))
                    {
                        return(numberResult);
                    }
                }
            }
            return(null);
        }
        public async Task ProcessActivty(string authHeader, Activity activity, Func <IBotContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);
            await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient);

            await base.ProcessActivityInternal(activity, callback).ConfigureAwait(false);
        }
        /// <summary>
        /// Primary adapter method for processing activities sent from channel.
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// Throws <see cref="ArgumentNullException"/> on null arguments.
        /// </summary>
        /// <param name="activity">The <see cref="Activity"/> to process.</param>
        /// <param name="callback">The code to run at the end of the adapter's middleware pipeline.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// If the task completes successfully, then if the activity's <see cref="Activity.Type"/>
        /// is <see cref="ActivityTypes.Invoke"/> and the corresponding key
        /// (<see cref="Activity.ChannelId"/> + <see cref="Activity.Id"/>) is found
        /// then an <see cref="InvokeResponse"/> is returned, otherwise null is returned.
        /// <para>This method registers the following services for the turn.<list type="bullet"/></para>
        /// </remarks>
        public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken = default(CancellationToken))
        {
            BotAssert.ActivityNotNull(activity);

            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }

            _logger.LogInformation($"Received an incoming activity.  ActivityId: {activity.Id}");

            using (var context = new TurnContext(this, activity))
            {
                await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);

                if (activity.Type == ActivityTypes.Invoke)
                {
                    var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeReponseKey);
                    if (activityInvokeResponse == null)
                    {
                        return(new InvokeResponse {
                            Status = (int)HttpStatusCode.NotImplemented
                        });
                    }
                    else
                    {
                        return((InvokeResponse)activityInvokeResponse.Value);
                    }
                }

                return(null);
            }
        }
Ejemplo n.º 12
0
        public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken)
        {
            BotAssert.ActivityNotNull(activity);

            _logger.LogInformation($"Received an incoming activity.  ActivityId: {activity.Id}");

            using (var context = new TurnContext(this, activity))
            {
                await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);

                // Handle Invoke scenarios, which deviate from the request/response model in that
                // the Bot will return a specific body and return code.
                if (activity.Type == ActivityTypes.Invoke)
                {
                    var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeReponseKey);
                    if (activityInvokeResponse == null)
                    {
                        return(new InvokeResponse {
                            Status = (int)HttpStatusCode.NotImplemented
                        });
                    }
                    else
                    {
                        return((InvokeResponse)activityInvokeResponse.Value);
                    }
                }

                // For all non-invoke scenarios, the HTTP layers above don't have to mess
                // withthe Body and return codes.
                return(null);
            }
        }
Ejemplo n.º 13
0
        public override async Task <InvokeResponse> ProcessActivityAsync(ClaimsIdentity claimsIdentity, Schema.Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken)
        {
            BotAssert.ActivityNotNull(activity);

            using (var context = new TurnContext(this, activity))
            {
                context.TurnState.Add <IIdentity>(BotIdentityKey, claimsIdentity);
                context.TurnState.Add(this.config);
                context.TurnState.Add(callback);

                await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);

                // Handle ExpectedReplies scenarios where the all the activities have been buffered and sent back at once
                // in an invoke response.
                if (context.Activity.DeliveryMode == DeliveryModes.ExpectReplies)
                {
                    return(new InvokeResponse {
                        Status = (int)HttpStatusCode.OK, Body = new ExpectedReplies(context.BufferedReplyActivities)
                    });
                }

                // Handle Invoke scenarios, which deviate from the request/request model in that
                // the Bot will return a specific body and return code.
                if (activity.Type == ActivityTypes.Invoke)
                {
                    return(new InvokeResponse {
                        Status = (int)HttpStatusCode.NotImplemented
                    });
                }

                // For all non-invoke scenarios, the HTTP layers above don't have to mess
                // with the Body and return codes.
                return(null);
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Used to validate the incoming text, expected on context.Request, is
        /// valid according to the rules defined in the validation steps.
        /// </summary>
        public override async Task <DateTimeResult> Recognize(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type == ActivityTypes.Message)
            {
                var message = context.Activity.AsMessageActivity();
                var results = _model.Parse(message.Text);
                if (results.Any())
                {
                    var result = results.First();
                    if (result.Resolution.Any())
                    {
                        var dateTimeResult = new DateTimeResult
                        {
                            Status = PromptStatus.Recognized,
                            Text   = result.Text
                        };

                        foreach (var resolution in result.Resolution)
                        {
                            var values = (List <Dictionary <string, string> >)resolution.Value;
                            if (values.Any())
                            {
                                dateTimeResult.Resolution.Add(ReadResolution(values.First()));
                                await Validate(context, dateTimeResult);

                                return(dateTimeResult);
                            }
                        }
                    }
                }
            }
            return(new DateTimeResult());
        }
Ejemplo n.º 15
0
        public override async Task <RangeResult> Recognize(ITurnContext context)
        {
            BotAssert.ContextNotNull(context);
            BotAssert.ActivityNotNull(context.Activity);
            if (context.Activity.Type != ActivityTypes.Message)
            {
                throw new InvalidOperationException("No Message to Recognize");
            }

            RangeResult      rangeResult = new RangeResult();
            IMessageActivity message     = context.Activity.AsMessageActivity();
            var results = _model.Parse(message.Text);

            if (results.Any())
            {
                var result = results.First();
                if (result.TypeName == "numberrange")
                {
                    string[] values = result.Resolution["value"].ToString().Trim('(', ')').Split(',');
                    if (float.TryParse(values[0], out float startValue) && float.TryParse(values[1], out float endValue))
                    {
                        rangeResult.Status = PromptStatus.Recognized;
                        rangeResult.Text   = result.Text;
                        rangeResult.Start  = startValue;
                        rangeResult.End    = endValue;
                        await Validate(context, rangeResult);
                    }
                }
            }
            return(rangeResult);
        }
        public async Task <InvokeResponse> ProcessActivity(ClaimsIdentity identity, Activity activity, Func <ITurnContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);

            using (var context = new TurnContext(this, activity))
            {
                context.Services.Add <IIdentity>("BotIdentity", identity);

                var connectorClient = await this.CreateConnectorClientAsync(activity.ServiceUrl, identity).ConfigureAwait(false);

                context.Services.Add <IConnectorClient>(connectorClient);

                await base.RunPipeline(context, callback).ConfigureAwait(false);

                // Handle Invoke scenarios, which deviate from the request/response model in that
                // the Bot will return a specific body and return code.
                if (activity.Type == ActivityTypes.Invoke)
                {
                    Activity invokeResponse = context.Services.Get <Activity>(InvokeReponseKey);
                    if (invokeResponse == null)
                    {
                        // ToDo: Trace Here
                        throw new InvalidOperationException("Bot failed to return a valid 'invokeResponse' activity.");
                    }
                    else
                    {
                        return((InvokeResponse)invokeResponse.Value);
                    }
                }

                // For all non-invoke scenarios, the HTTP layers above don't have to mess
                // withthe Body and return codes.
                return(null);
            }
        }
        public void TrackCustomEvent(IActivity activity, string eventName = EventTypes.CustomEvent, IDictionary <string, string> properties = null)
        {
            BotAssert.ActivityNotNull(activity);

            var activityAdapter = new ActivityAdapter(activity);

            activityAdapter.TrackCustomEvent(this.telemetryClient, this.settings, eventName, properties);
        }
Ejemplo n.º 18
0
        public async Task TrackMessageSentiment(IMessageActivity activity)
        {
            BotAssert.ActivityNotNull(activity);

            var activityAdapter = new ActivityAdapter(activity);

            await activityAdapter.TrackMessageSentiment(this.telemetryClient, this.settings, this.sentimentClient).ConfigureAwait(false);
        }
        /// <summary>
        /// Creates a turn context and runs the middleware pipeline for an incoming activity.
        /// </summary>
        /// <param name="authHeader">The HTTP authentication header of the request.</param>
        /// <param name="activity">The incoming activity.</param>
        /// <param name="callback">The code to run at the end of the adapter's middleware
        /// pipeline.</param>
        /// <returns>A task that represents the work queued to execute. If the activity type
        /// was 'Invoke' and the corresponding key (channelId + activityId) was found
        /// then an InvokeResponse is returned, otherwise null is returned.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="activity"/> is <c>null</c>.</exception>
        /// <exception cref="UnauthorizedAccessException">
        /// authentication failed.</exception>
        /// <remarks>Call this method to reactively send a message to a conversation.
        /// <para>This method registers the following services for the turn.<list type="bullet">
        /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item>
        /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item>
        /// </list></para>
        /// </remarks>
        /// <seealso cref="ContinueConversation(string, ConversationReference, Func{ITurnContext, Task})"/>
        /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task}, System.Threading.CancellationTokenSource)"/>
        public async Task <InvokeResponse> ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);

            var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient).ConfigureAwait(false);

            return(await ProcessActivity(claimsIdentity, activity, callback).ConfigureAwait(false));
        }
        /// <summary>
        /// Log an activity to the transcript.
        /// </summary>
        /// <param name="activity">Activity being logged.</param>
        /// <returns>A <see cref="Task"/>A task that represents the work queued to execute.</returns>
        public async Task LogActivityAsync(IActivity activity)
        {
            BotAssert.ActivityNotNull(activity);

            switch (activity.Type)
            {
            case ActivityTypes.MessageUpdate:
            {
                var activityAndBlob = await InnerReadBlobAsync(activity).ConfigureAwait(false);

                if (activityAndBlob.Item1 != null)
                {
                    var updatedActivity = JsonConvert.DeserializeObject <Activity>(JsonConvert.SerializeObject(activity));
                    updatedActivity.Type           = ActivityTypes.Message; // fixup original type (should be Message)
                    updatedActivity.LocalTimestamp = activityAndBlob.Item1.LocalTimestamp;
                    updatedActivity.Timestamp      = activityAndBlob.Item1.Timestamp;
                    await LogActivityToBlobClientAsync(updatedActivity, activityAndBlob.Item2, true).ConfigureAwait(false);
                }

                return;
            }

            case ActivityTypes.MessageDelete:
            {
                var activityAndBlob = await InnerReadBlobAsync(activity).ConfigureAwait(false);

                if (activityAndBlob.Item1 != null)
                {
                    // tombstone the original message
                    var tombstonedActivity = new Activity()
                    {
                        Type           = ActivityTypes.MessageDelete,
                        Id             = activityAndBlob.Item1.Id,
                        From           = new ChannelAccount(id: "deleted", role: activityAndBlob.Item1.From.Role),
                        Recipient      = new ChannelAccount(id: "deleted", role: activityAndBlob.Item1.Recipient.Role),
                        Locale         = activityAndBlob.Item1.Locale,
                        LocalTimestamp = activityAndBlob.Item1.Timestamp,
                        Timestamp      = activityAndBlob.Item1.Timestamp,
                        ChannelId      = activityAndBlob.Item1.ChannelId,
                        Conversation   = activityAndBlob.Item1.Conversation,
                        ServiceUrl     = activityAndBlob.Item1.ServiceUrl,
                        ReplyToId      = activityAndBlob.Item1.ReplyToId,
                    };

                    await LogActivityToBlobClientAsync(tombstonedActivity, activityAndBlob.Item2, true).ConfigureAwait(false);
                }

                return;
            }

            default:
                var blobName   = GetBlobName(activity);
                var blobClient = _containerClient.Value.GetBlobClient(blobName);
                await LogActivityToBlobClientAsync(activity, blobClient).ConfigureAwait(false);

                return;
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Log an activity to the transcript.
        /// </summary>
        /// <param name="activity">Activity being logged.</param>
        /// <returns>A <see cref="Task"/>A task that represents the work queued to execute.</returns>
        public async Task LogActivityAsync(IActivity activity)
        {
            BotAssert.ActivityNotNull(activity);

            switch (activity.Type)
            {
                case ActivityTypes.MessageUpdate:
                    {
                        var blob = await FindActivityBlobAsync(activity).ConfigureAwait(false);
                        if (blob != null)
                        {
                            var originalActivity = JsonConvert.DeserializeObject<Activity>(await blob.DownloadTextAsync().ConfigureAwait(false));
                            var updatedActivity = JsonConvert.DeserializeObject<Activity>(JsonConvert.SerializeObject(activity));
                            updatedActivity.Type = ActivityTypes.Message; // fixup original type (should be Message)
                            updatedActivity.LocalTimestamp = originalActivity.LocalTimestamp;
                            updatedActivity.Timestamp = originalActivity.Timestamp;
                            await LogActivityAsync(updatedActivity, blob).ConfigureAwait(false);
                        }

                        return;
                    }

                case ActivityTypes.MessageDelete:
                    {
                        var blob = await FindActivityBlobAsync(activity).ConfigureAwait(false);
                        if (blob != null)
                        {
                            var originalActivity = JsonConvert.DeserializeObject<Activity>(await blob.DownloadTextAsync().ConfigureAwait(false));

                            // tombstone the original message
                            var tombstonedActivity = new Activity()
                            {
                                Type = ActivityTypes.MessageDelete,
                                Id = originalActivity.Id,
                                From = new ChannelAccount(id: "deleted", role: originalActivity.From.Role),
                                Recipient = new ChannelAccount(id: "deleted", role: originalActivity.Recipient.Role),
                                Locale = originalActivity.Locale,
                                LocalTimestamp = originalActivity.Timestamp,
                                Timestamp = originalActivity.Timestamp,
                                ChannelId = originalActivity.ChannelId,
                                Conversation = originalActivity.Conversation,
                                ServiceUrl = originalActivity.ServiceUrl,
                                ReplyToId = originalActivity.ReplyToId,
                            };

                            await LogActivityAsync(tombstonedActivity, blob).ConfigureAwait(false);
                        }

                        return;
                    }

                default:
                    var blobName = GetBlobName(activity);
                    var blobReference = this.Container.Value.GetBlockBlobReference(blobName);
                    await LogActivityAsync(activity, blobReference).ConfigureAwait(false);
                    return;
            }
        }
Ejemplo n.º 22
0
        public async Task Receive(string authHeader, Activity activity)
        {
            BotAssert.ActivityNotNull(activity);
            await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient);

            if (this.OnReceive != null)
            {
                await OnReceive(activity).ConfigureAwait(false);
            }
        }
Ejemplo n.º 23
0
        public async Task ProcessActivity(string authHeader, Activity activity, Func <IBotContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);
            ClaimsIdentity claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient);

            // For requests from channel App Id is in Audience claim of JWT token. For emulator it is in AppId claim. For
            // unauthenticated requests we have anonymouse identity provided auth is disabled.
            string botAppId = GetBotId(claimsIdentity);
            var    context  = new BotFrameworkBotContext(botAppId, this, activity);
            await base.RunPipeline(context, callback).ConfigureAwait(false);
        }
        public async Task <AlexaResponseBody> ProcessActivity(AlexaRequestBody alexaRequest, AlexaOptions alexaOptions, BotCallbackHandler callback)
        {
            TurnContext context = null;

            try
            {
                Options = alexaOptions;

                var activity = RequestToActivity(alexaRequest);
                BotAssert.ActivityNotNull(activity);

                context = new TurnContext(this, activity);

                if (alexaRequest.Session.Attributes != null && alexaRequest.Session.Attributes.Any())
                {
                    context.TurnState.Add("AlexaSessionAttributes", alexaRequest.Session.Attributes);
                }
                else
                {
                    context.TurnState.Add("AlexaSessionAttributes", new Dictionary <string, string>());
                }

                context.TurnState.Add("AlexaResponseDirectives", new List <IAlexaDirective>());

                Responses = new Dictionary <string, List <Activity> >();

                await base.RunPipelineAsync(context, callback, default(CancellationToken)).ConfigureAwait(false);

                var key = $"{activity.Conversation.Id}:{activity.Id}";

                try
                {
                    AlexaResponseBody response = null;
                    var activities             = Responses.ContainsKey(key) ? Responses[key] : new List <Activity>();
                    response = CreateResponseFromLastActivity(activities, context);
                    response.SessionAttributes = context.AlexaSessionAttributes();
                    return(response);
                }
                finally
                {
                    if (Responses.ContainsKey(key))
                    {
                        Responses.Remove(key);
                    }
                }
            }
            catch (Exception ex)
            {
                await alexaOptions.OnTurnError(context, ex);

                throw;
            }
        }
        /// <summary>
        /// Applies all relevant Conversation related identifies to an activity. This effectivly
        /// couples a blank Activity to a conversation.
        /// </summary>
        /// <param name="activity">The activity to update. Existing values in the Activity will be overwritten.</param>
        /// <param name="reference">The ConversationReference from which to pull the relevant conversation information</param>
        /// <remarks>
        /// This method applies the following values from ConversationReference:
        /// ChannelId
        /// ServiceUrl
        /// Conversation
        /// Bot (assigned to the .From property on the Activity)
        /// User (assigned to the .Recipient on the Activity)
        /// ActivityId (assigned as the ReplyToId on the Activity)
        /// </remarks>
        public static void ApplyConversationReference(IActivity activity, ConversationReference reference)
        {
            BotAssert.ActivityNotNull(activity);
            BotAssert.ConversationReferenceNotNull(reference);

            activity.ChannelId    = reference.ChannelId;
            activity.ServiceUrl   = reference.ServiceUrl;
            activity.Conversation = reference.Conversation;
            activity.From         = reference.Bot;
            activity.Recipient    = reference.User;
            activity.ReplyToId    = reference.ActivityId;
        }
        public async Task ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback)
        {
            BotAssert.ActivityNotNull(activity);
            var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient);

            var context = new TurnContext(this, activity);

            context.Services.Add <IIdentity>("BotIdentity", claimsIdentity);
            var connectorClient = await this.CreateConnectorClientAsync(activity.ServiceUrl, claimsIdentity);

            context.Services.Add <IConnectorClient>(connectorClient);
            await base.RunPipeline(context, callback).ConfigureAwait(false);
        }
Ejemplo n.º 27
0
        public void TrackCustomEvent(
            IActivity activity,
            string eventName = EventTypes.CustomEvent,
            IDictionary <string, string> properties = null)
        {
            BotAssert.ActivityNotNull(activity);

            var builder        = new EventTelemetryBuilder(activity, this.settings, properties);
            var eventTelemetry = builder.Build();

            eventTelemetry.Name = string.IsNullOrWhiteSpace(eventName) ? EventTypes.CustomEvent : eventName;
            this.telemetryClient.TrackEvent(eventTelemetry);
        }
Ejemplo n.º 28
0
        public async Task ProcessActivityAsync(Activity activity, string msAppId, ConversationReference conversationRef, BotCallbackHandler callback, CancellationToken cancellationToken)
        {
            BotAssert.ActivityNotNull(activity);

            activity.ApplyConversationReference(conversationRef, true);

            await ContinueConversationAsync(
                msAppId,
                conversationRef,
                async (ITurnContext proactiveContext, CancellationToken ct) =>
            {
                using (var contextWithActivity = new TurnContext(this, activity))
                {
                    contextWithActivity.TurnState.Add(proactiveContext.TurnState.Get <IConnectorClient>());
                    await base.RunPipelineAsync(contextWithActivity, callback, cancellationToken);

                    if (contextWithActivity.Activity.Name == "handoff.status")
                    {
                        var conversationStateAccessors = _conversationState.CreateProperty <LoggingConversationData>(nameof(LoggingConversationData));
                        var conversationData           = await conversationStateAccessors.GetAsync(contextWithActivity, () => new LoggingConversationData());

                        Activity replyActivity;
                        var state = (contextWithActivity.Activity.Value as JObject)?.Value <string>("state");
                        if (state == "typing")
                        {
                            replyActivity = new Activity
                            {
                                Type = ActivityTypes.Typing,
                                Text = "agent is typing",
                            };
                        }
                        else if (state == "accepted")
                        {
                            replyActivity = MessageFactory.Text("An agent has accepted the conversation and will respond shortly.");
                            await _conversationState.SaveChangesAsync(contextWithActivity);
                        }
                        else if (state == "completed")
                        {
                            replyActivity = MessageFactory.Text("The agent has closed the conversation.");
                        }
                        else
                        {
                            replyActivity = MessageFactory.Text($"Conversation status changed to '{state}'");
                        }

                        await contextWithActivity.SendActivityAsync(replyActivity);
                    }
                }
            },
                cancellationToken).ConfigureAwait(false);
        }
Ejemplo n.º 29
0
        public void TrackIntent(IActivity activity, RecognizerResult result)
        {
            BotAssert.ActivityNotNull(activity);

            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            var activityAdapter         = new ActivityAdapter(activity);
            var recognizerResultAdapter = new RecognizerResultAdapter(result);

            activityAdapter.TrackIntent(recognizerResultAdapter.IntentResult, this.telemetryClient, this.settings);
        }
        public async Task <object> ProcessActivity(Payload actionPayload, BotCallbackHandler callback, string uniqueRequestId = null)
        {
            TurnContext context = null;

            try
            {
                var activity = RequestToActivity(actionPayload, uniqueRequestId);
                BotAssert.ActivityNotNull(activity);

                context = new TurnContext(this, activity);

                context.TurnState.Add("GoogleUserId", activity.From.Id);

                Responses = new Dictionary <string, List <Activity> >();

                await base.RunPipelineAsync(context, callback, default(CancellationToken)).ConfigureAwait(false);

                var key = $"{activity.Conversation.Id}:{activity.Id}";

                try
                {
                    object response   = null;
                    var    activities = Responses.ContainsKey(key) ? Responses[key] : new List <Activity>();

                    if (WebhookType == GoogleWebhookType.DialogFlow)
                    {
                        response = CreateDialogFlowResponseFromLastActivity(activities, context);
                    }
                    else
                    {
                        response = CreateConversationResponseFromLastActivity(activities, context);
                    }

                    return(response);
                }
                finally
                {
                    if (Responses.ContainsKey(key))
                    {
                        Responses.Remove(key);
                    }
                }
            }
            catch (Exception ex)
            {
                await OnTurnError(context, ex);

                throw;
            }
        }