/// <summary> /// Initializes a new instance of the <see cref="GraphAuthenticationBot"/> class. /// </summary> /// <param name="accessors">State accessors for the bot.</param> public GraphAuthenticationBot(GraphAuthenticationBotAccessors accessors) { if (string.IsNullOrWhiteSpace(ConnectionSettingName)) { throw new InvalidOperationException("ConnectionSettingName must be configured prior to running the bot."); } _stateAccessors = accessors ?? throw new ArgumentNullException(nameof(accessors)); _dialogs = new DialogSet(_stateAccessors.ConversationDialogState); _dialogs.Add(OAuthHelpers.Prompt(ConnectionSettingName)); _dialogs.Add(new ChoicePrompt("choicePrompt")); _dialogs.Add(new WaterfallDialog("graphDialog", new WaterfallStep[] { PromptStepAsync, ProcessStepAsync })); }
/// <summary> /// Waterfall dialog step to process the command sent by the user. /// </summary> /// <param name="step">A <see cref="WaterfallStepContext"/> provides context for the current waterfall step.</param> /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> representing the operation result of the operation.</returns> private async Task <DialogTurnResult> ProcessStepAsync(WaterfallStepContext step, CancellationToken cancellationToken) { if (step.Result != null) { // We do not need to store the token in the bot. When we need the token we can // send another prompt. If the token is valid the user will not need to log back in. // The token will be available in the Result property of the task. var tokenResponse = step.Result as TokenResponse; // If we have the token use the user is authenticated so we may use it to make API calls. if (tokenResponse?.Token != null) { var parts = _stateAccessors.CommandState.GetAsync(step.Context, () => string.Empty, cancellationToken: cancellationToken).Result.Split(' '); string command = parts[0].ToLowerInvariant(); if (command == "me") { await OAuthHelpers.ListMeAsync(step.Context, tokenResponse); } else if (command.StartsWith("send")) { await OAuthHelpers.SendMailAsync(step.Context, tokenResponse, parts[1]); } else if (command.StartsWith("recent")) { await OAuthHelpers.ListRecentMailAsync(step.Context, tokenResponse); } else if (command.StartsWith("token")) { await step.Context.SendActivityAsync($"Your token is: {tokenResponse.Token}", cancellationToken : cancellationToken); } else if (command.StartsWith("continue")) { await OAuthHelpers.ContinueAsync(step.Context, tokenResponse); } else if (command.StartsWith("welcome")) { await OAuthHelpers.SendWelcomeCardMessageAsync(step.Context, cancellationToken); } await _stateAccessors.CommandState.DeleteAsync(step.Context, cancellationToken); } } else { await step.Context.SendActivityAsync("We couldn't log you in. Please try again later.", cancellationToken : cancellationToken); } return(await step.EndDialogAsync(cancellationToken : cancellationToken)); }
/// <summary> /// This controls what happens when an <see cref="Activity"/> gets sent to the bot. /// </summary> /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed /// for processing this conversation turn. </param> /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns> public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { DialogContext dc = null; switch (turnContext.Activity.Type) { case ActivityTypes.Message: await ProcessInputAsync(turnContext, cancellationToken); break; case ActivityTypes.Event: case ActivityTypes.Invoke: // This handles the Microsoft Teams Invoke Activity sent when magic code is not used. // See: https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-oauth-card#getting-started-with-oauthcard-in-teams // Manifest Schema Here: https://docs.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema // It also handles the Event Activity sent from The Emulator when the magic code is not used. // See: https://blog.botframework.com/2018/08/28/testing-authentication-to-your-bot-using-the-bot-framework-emulator/ // Sanity check the activity type and channel Id. if (turnContext.Activity.Type == ActivityTypes.Invoke && turnContext.Activity.ChannelId != "msteams") { throw new InvalidOperationException("The Invoke type is only valid onthe MSTeams channel."); } dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken); await dc.ContinueDialogAsync(cancellationToken); if (!turnContext.Responded) { await dc.BeginDialogAsync("graphDialog", cancellationToken : cancellationToken); } break; case ActivityTypes.ConversationUpdate: // Send a HeroCard as a welcome message when a new user joins the conversation. await OAuthHelpers.SendWelcomeMessageAsync(turnContext, cancellationToken : cancellationToken); break; } }