microsoft / botframework-sdk

Bot Framework provides the most comprehensive experience for building conversation applications.
MIT License
7.5k stars 2.44k forks source link

[Question] Bot with Google Calendar Api #3340

Closed MarcoAntonino closed 6 years ago

MarcoAntonino commented 7 years ago

System Information

Bot Info As registered in the Bot Developer Portal at https://dev.botframework.com

Issue Description

Hello, I'm trying to create a bot that can show user the events on his Google Calendar. When the user writes the "cal" command, the bot shows all the events. When I run the bot on the localhost, this works perfectly. But when I send the command "cal" on the remote server on AppHarbor, I get this message: Request to 'https://calbot00.apphb.com/api/messages' failed: [500] Internal Server Error" and this serviceUrl.

As you can see, I'm writing every step on text file called "ex.txt". With the "command read" I print every line of the ex.txt file on the bot dialog. Reading ex.txt, the last comment on ex.txt is "UserCredential credential created" so I guess that there are some problems in the part of the code that starts with using (var stream = new FileStream( For the Google Calendar Api I'm following this guide

Code Example

using System;  
using System.Threading.Tasks;  
using Microsoft.Bot.Builder.Dialogs;  
using Microsoft.Bot.Connector;  
using Google.Apis.Auth.OAuth2;  
using Google.Apis.Calendar.v3;  
using Google.Apis.Calendar.v3.Data;  
using Google.Apis.Services;  
using Google.Apis.Util.Store;  
using System.Collections.Generic;  
using System.IO;  
using System.Linq;  
using System.Text;  
using System.Threading;  
using System.Diagnostics;

namespace CalBot00.Dialogs  
{
    [Serializable]
    public class RootDialog : IDialog<object>
    {
        static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
        static string ApplicationName = "Google Calendar API .NET Quickstart";

        public Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);

            return Task.CompletedTask;
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
        {

            var activity = await result as Activity;            
            //string calendar = "cal";
            string aula = "Aula";
            //string help = "/help";

            // calculate something for us to return

            switch (activity.Text)
            {
                case "hi":
                    await context.PostAsync($"Hello you too");
                    break;

                case "cal":
                    using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
                    {
                        file.WriteLine(DateTime.Now + " ***Command 'cal' called***");
                    }
                    Events events = GetEvents();

                    await context.PostAsync($"Upcoming events:");
                    if (events!=null)
                    {
                        if (events.Items != null && events.Items.Count > 0)
                        {
                            foreach (var eventItem in events.Items)
                            {
                                string when = eventItem.Start.DateTime.ToString();
                                if (String.IsNullOrEmpty(when))
                                {
                                    when = eventItem.Start.Date;
                                }
                                await context.PostAsync($"{eventItem.Summary} {eventItem.Location} ({when})");
                                //Console.WriteLine("{0} ({1})", eventItem.Summary, when);
                            }
                        }
                        else
                        {
                            Console.WriteLine("No upcoming events found.");
                        }
                    }
                    else
                    {
                        await context.PostAsync($"Events è vuoto");
                    }
                    using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
                    {
                        file.WriteLine(DateTime.Now + " ***End of cal***");
                    }
                    break;

                case "aula":
                    Events eventsWithAula = GetEvents();
                    if (eventsWithAula.Items != null && eventsWithAula.Items.Count > 0)
                    {
                        foreach (var eventItem in eventsWithAula.Items)
                        {
                            string when = eventItem.Start.DateTime.ToString();
                            if (eventItem.Location.Contains("Aula"))
                            {
                                when = eventItem.Start.Date;
                                await context.PostAsync($"{eventItem.Summary} ({when})");
                            }

                        }

                    }
                    break;
                case "pippo":
                    await context.PostAsync($"pluto");
                    break;

                case "file":

                    string[] filePaths = Directory.GetFiles(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory));
                    for (int i = 0; i < filePaths.Length; ++i)
                    {
                        string path = filePaths[i];
                        Console.WriteLine(System.IO.Path.GetFileName(path));
                        await context.PostAsync($"{System.IO.Path.GetFileName(path)}");
                    }

                    break;

                case "directory":

                    string[] directoriePaths = Directory.GetDirectories(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory));
                    for (int i = 0; i < directoriePaths.Length; ++i)
                    {
                        string path = directoriePaths[i];
                        Console.WriteLine(System.IO.Path.GetFileName(path));
                        await context.PostAsync($"{System.IO.Path.GetFileName(path)}");
                    }

                    break;

                case "write":

                    using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
                    {
                        file.WriteLine(DateTime.Now + " Command 'write' called");
                    }

                    await context.PostAsync($"Done");

                    break;

                case "read":
                    string[] lines = System.IO.File.ReadAllLines(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt");

                    foreach (string line in lines)
                    {
                        // Use a tab to indent each line of the file.
                        // Console.WriteLine("\t" + line);
                        await context.PostAsync($"\t {line}");
                    }

                    break;

                default:
                    int length = (activity.Text ?? string.Empty).Length;
                    await context.PostAsync($"You sent {activity.Text} which was {length} characters");
                    break;
            }

            // return our reply to the user

            context.Wait(MessageReceivedAsync);
        }

        private static Events GetEvents()
        {
            using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
            {
                file.WriteLine(DateTime.Now + " Entered in GetEvents()");
            }

            UserCredential credential;

            using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
            {
                file.WriteLine(DateTime.Now + " UserCredential credential created");
            }

            using (var stream =
                new FileStream(AppDomain.CurrentDomain.BaseDirectory + @"client_secret.json", FileMode.Open, FileAccess.Read))
            {
                string credPath = System.Environment.GetFolderPath(
                    System.Environment.SpecialFolder.Personal);
                credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json");

                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true)).Result;
                System.Diagnostics.Debug.WriteLine("Credential file saved to: " + credPath);
                using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
                {
                    file.WriteLine(DateTime.Now + " Credential file saved to: " + credPath);
                }
            }            

            // Create Google Calendar API service.
            var service = new CalendarService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = ApplicationName,
            });

            using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
            {
                file.WriteLine(DateTime.Now + " var service instanziated ");
            }

            // Define parameters of request.
            EventsResource.ListRequest request = service.Events.List("primary");
            request.TimeMin = DateTime.Now;
            request.ShowDeleted = false;
            request.SingleEvents = true;
            request.MaxResults = 10;
            request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;

            using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
            {
                file.WriteLine(DateTime.Now + " Defined request parameters ");
            }

            // List events.
            Events events = request.Execute();

            using (System.IO.StreamWriter file =
                        new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + @"ex.txt", true))
            {
                file.WriteLine(DateTime.Now + " Events istaziated ");
            }

            return events;

        }

    }
}

Expected Behavior

Sendig the command "cal", the bot should print all the events in a google calendar. This in my localhost, works

Actual Results

On the left the behavior in localhost, on the right the issue in remote server. test

Thanks for the help, Marco

JasonSowers commented 7 years ago

This is a very specific question unfortunately, it may be hard to find someone experienced with this.

JasonSowers commented 7 years ago

@MarcoAntonino did you find a solution?

MarcoAntonino commented 7 years ago

Hi @JasonSowers I found a workaround but I'm not so satisfied.

I'm using the google API for Calendars (no OAuth). But there are a couple of limitations: first they works only with public calendars and second I'm pretty sure the you can only read this calendars so you cannot add, modify or delete events.

For what I need it's ok, but It would be great if I could use the OAuth.

Here's the guide that I followed for the API: link