MetalMad
MetalMad

Reputation: 446

Microsoft BotFramework : Integrate FormFlow and Dialog with Authentication

I have developed a bot with MS Bot Framework using Dialog with an authentication process on Twitter. ( I followed the facebook github project)

I added a business logic flow and, reading MS documentation, I followed the FormFlow best practice .

Now I have a Dialog with the core of the Twitter Authentication and a FormFlow with my BL. At time being I am in difficulty to merge the Auth process and the BL process.

My goal is :

Do you have any suggestion about what best way to merge that ? Can I run my FormFlow only if Authentication has been done keeping separated the implementations?

some pieces of code

This is my Dialog with Authorization

 public static readonly IDialog<string> dialog = Chain
            .PostToChain()
            .Switch(
             new Case<IMessageActivity, IDialog<string>>((msg) =>
                {
                    var regex = new Regex("^login", RegexOptions.IgnoreCase);
                    return regex.IsMatch(msg.Text);
                }, (ctx, msg) =>
                {
                    // User wants to login, send the message to Twitter Auth Dialog
                    return Chain.ContinueWith(new SimpleTwitterAuthDialog(msg),
                                async (context, res) =>
                                {
                                    // The Twitter Auth Dialog completed successfully and returend the access token in its results
                                    var token = await res;
                                    var name = await TwitterHelpers.GetTwitterProfileName(token);
                                    context.UserData.SetValue("name", name);



                                      context.PrivateConversationData.SetValue<bool>("isLogged", true);
                                        return Chain.Return($"Your are logged in as: {name}");
                                    });
                    }),

            new DefaultCase<IMessageActivity, IDialog<string>>((ctx, msg) =>
                {

                    string token;
                    string name = string.Empty;
                    if (ctx.PrivateConversationData.TryGetValue(AuthTokenKey, out token) && ctx.UserData.TryGetValue("name", out name))
                    {
                        var validationTask = TwitterHelpers.ValidateAccessToken(token);
                        validationTask.Wait();
                        if (validationTask.IsCompleted && validationTask.Result)
                        {

                            Chain.ContinueWith(new TwitterDialog(),
                                                                async (context2, res2) =>
                                                                {

                                                                    var result2 = await res2;
                                                                    return Chain.Return($"Done.");
                                                                });

                            return Chain.Return($"Your are logged in as: {name}");
                        }
                        else
                        {
                            return Chain.Return($"Your Token has expired! Say \"login\" to log you back in!");
                        }
                    }
                    else
                    {
                        return Chain.Return("Say \"login\" when you want to login to Twitter!");
                    }
                })
            ).Unwrap().PostToUser();

This is my FormFlow with BL

        public static IForm<Tweet> BuildForm()
            {

                OnCompletionAsyncDelegate<Tweet> processTweet = async (context, state) =>
                {

                    await context.PostAsync($"We are currently processing your tweet . We will message you the status. );
                    //...some code here ... 


                };

                return new FormBuilder<Tweet>()
                        .Message("Tweet bot !")
                        .Field(nameof(TweetHashtags))
                        .Field(nameof(Tweet.DeliveryTime), "When do you want publish your tweet? {||}")`
                        .Confirm("Are you sure ?")
                        .AddRemainingFields()
                        .Message("Thanks, your tweet will be post!")
                        .OnCompletion(processTweet)
                        .Build();

This is controller

public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
        {
               // QUESTION 1 : 
               // when user send the first message, How can I check if user is already logged in or not?

               //QUESTION 2:
               // Based on Question 1 answer,  How can switch between Auth Dialog and FormFlow  if user is not logged in ?

              //QUESTION 3:
              // is this the right place where I have to check the Question 1 and Question 2 or I have to do in another place ? 

}

Upvotes: 1

Views: 975

Answers (1)

Ezequiel Jadib
Ezequiel Jadib

Reputation: 14787

I would separate this in two dialogs, with a root dialog, that will determine if the user is authenticated or not. If it's not, you can launch the Auth Dialog; otherwise you can just call your FormFlow.

You shouldn't perform the checks in the Controller. The controller should just call the RootDialog. In general, when things starts to grow I prefer to use custom dialogs than a Chain.

You can take a look at AuthBot to get an idea of how this approach is done. In the samples, you will see there is an ActionDialog (a root dialog) that it's calling the AzureAuthDialog when required.

If you want to check a more complex sample; also using AuthBot and this approach, check AzureBot.

Upvotes: 1

Related Questions