private DisambiguateRoomDialog() : base(Id)
        {
            var recognizer = new DateTimeRecognizer(Culture.English);
            var model      = recognizer.GetDateTimeModel();

            Dialogs.Add(Id, new WaterfallStep[]
            {
                async(dc, args, next) =>
                {
                    var stateWrapper = new DisambiguateRoomDialogStateWrapper(dc.ActiveDialog.State)
                    {
                        Booking = (BookingRequest)args["bookingRequest"]
                    };
                    var bookingRequest = stateWrapper.Booking;

                    bookingRequest.AvailableRooms = (await MicrosoftGraphExtensions.GetMicrosoftGraphFindMeetingRooms(
                                                         dc.Context.Services.Get <ConversationAuthToken>(AzureAdAuthMiddleware.AUTH_TOKEN_KEY).AccessToken)).ToArray();

                    if (string.IsNullOrEmpty(bookingRequest.Room))
                    {
                        var roomChoices = new List <Choice> {
                            new Choice {
                                Value = "No preference"
                            }
                        };
                        roomChoices.AddRange(from room in bookingRequest.AvailableRooms select new Choice {
                            Value = room.DisplayName
                        });

                        await dc.Prompt("choicePrompt", "Do you have a preference which room?", new ChoicePromptOptions
                        {
                            Choices = roomChoices
                        }).ConfigureAwait(false);
                    }
                    else
                    {
                        await dc.End();
                    }
                },
                async(dc, args, next) =>
                {
                    await dc.End(new Dictionary <string, object>
                    {
                        ["Value"] = ((FoundChoice)args["Value"]).Value
                    });
                }
            });

            Dialogs.Add("choicePrompt", new ChoicePrompt("en"));
        }
        public async Task UserConsented(string code, string state)
        {
            var httpClient = new HttpClient();

            // get an access token from azure ad
            var accessToken = await httpClient.GetAzureAdToken(azureAdTenant, code, clientId, userConsentRedirectUri, clientSecret, permissionsRequested);

            // find 1 hour meeting slots in the next 24 hours in room
            var meetingTimes = await MicrosoftGraphExtensions.GetMicrosoftGraphFindMeeting(accessToken, DateTime.Now, DateTime.Now.AddDays(24), "PT1H", "Board room", "*****@*****.**");

            foreach (var meeting in meetingTimes.MeetingTimeSuggestions)
            {
                Console.WriteLine($"Meeting from {DateTime.Parse(meeting.MeetingTimeSlot.Start.DateTime)} to {DateTime.Parse(meeting.MeetingTimeSlot.End.DateTime)}");
            }
        }
        private SearchGraphDialog() : base(Id)
        {
            Dialogs.Add(Id, new WaterfallStep[]
            {
                async(dc, args, next) =>
                {
                    var stateWrapper = new SearchGraphDialogStateWrapper(dc.ActiveDialog.State)
                    {
                        Booking = (BookingRequest)args["bookingRequest"]
                    };
                    var bookingEnquiry = (BookingRequest)args["bookingRequest"];

                    var rooms = bookingEnquiry.Room == "No preference" ? (from room in bookingEnquiry.AvailableRooms select room.UserPrincipalName) : new[] { bookingEnquiry.AvailableRooms.FirstOrDefault(x => x.DisplayName == bookingEnquiry.Room).UserPrincipalName };

                    // 15. query Office 365 Graph for availability
                    var meetings = await MicrosoftGraphExtensions.GetMicrosoftGraphFindMeeting(
                        dc.Context.Services.Get <ConversationAuthToken>(AzureAdAuthMiddleware.AUTH_TOKEN_KEY).AccessToken,
                        bookingEnquiry.Start.Value,
                        bookingEnquiry.Start.Value + XmlConvert.ToTimeSpan(bookingEnquiry.MeetingDuration),
                        bookingEnquiry.MeetingDuration,
                        rooms.ToArray());

                    var bookingChoices = new List <(string, object)>();
                    foreach (var suggestion in meetings.MeetingTimeSuggestions)
                    {
                        foreach (var location in suggestion.Locations)
                        {
                            var display = $"{bookingEnquiry.AvailableRooms.FirstOrDefault(x => x.UserPrincipalName.ToLower() == location.LocationEmailAddress.ToLower()).DisplayName}: {DateTime.Parse(suggestion.MeetingTimeSlot.Start.DateTime).DayOfWeek} {DateTime.Parse(suggestion.MeetingTimeSlot.Start.DateTime).ToString("HH:mm")} - {DateTime.Parse(suggestion.MeetingTimeSlot.End.DateTime).ToString("HH:mm")}";
                            var value   = new { start = DateTime.Parse(suggestion.MeetingTimeSlot.Start.DateTime), end = DateTime.Parse(suggestion.MeetingTimeSlot.End.DateTime), roomEmail = location.LocationEmailAddress };
                            bookingChoices.Add((display, JsonConvert.SerializeObject(value)));
                        }
                    }

                    if (bookingChoices.Count == 0)
                    {
                        await dc.Context.SendActivity(dc.Context.Activity.CreateReply("Couldn't find any availability for that timeslot. A future improvement might be to widen the search by location or timeslots"));
                        dc.EndAll();
                    }
                    else
                    {
                        // 16. Present the choices back to the user as an adaptive card (see adaptivecards.io)
                        var activity = dc.Context.Activity.CreateReply();
                        activity.AddAdaptiveCardChoiceForm(bookingChoices.ToArray());
                        await dc.Context.SendActivity(activity);
                    }
                },
                async(dc, args, next) =>
                {
                    if (args["Activity"] is Activity activity && activity.Value != null && ((dynamic)activity.Value).chosenRoom is JValue chosenRoom)
                    {
                        dynamic requestedBooking = JsonConvert.DeserializeObject <ExpandoObject>((string)chosenRoom.Value);
                        // 17. Finally book the meeting
                        var meetingWebLink = await MicrosoftGraphExtensions.BookMicrosoftGraphMeeting(dc.Context.Services.Get <ConversationAuthToken>(AzureAdAuthMiddleware.AUTH_TOKEN_KEY).AccessToken,
                                                                                                      "Booked meeting", requestedBooking.roomEmail, requestedBooking.start, requestedBooking.end);

                        var confirmation = activity.CreateReply();
                        // 18. And send back a confirmation card
                        CardExtensions.AddAdaptiveCardRoomConfirmationAttachment(confirmation, requestedBooking.roomEmail, $"{requestedBooking.start.DayOfWeek} {requestedBooking.start.ToString("HH:mm")}", $"{requestedBooking.start.DayOfWeek} {requestedBooking.end.ToString("HH:mm")}", meetingWebLink);
                        await dc.Context.SendActivity(confirmation);
                        await dc.End();
                    }