From a1655dbe435c467d0014aca897cc5ea8958ad55f Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 10 Jun 2021 15:57:08 -0300 Subject: [PATCH 1/2] Update VA template --- templates/csharp/VA/VA.Tests/BotTestBase.cs | 14 ++++- templates/csharp/VA/VA.Tests/VA.Tests.csproj | 1 + .../VA/VA/Bots/DefaultActivityHandler.cs | 61 ++++++++++++++++++- templates/csharp/VA/VA/Dialogs/MainDialog.cs | 5 +- .../VA/Extensions/InvokeActivityExtensions.cs | 39 ++++++++++++ .../VA/Extensions/InvokeResponseExtensions.cs | 57 +++++++++++++++++ .../VA/VA/Models/SkillCardActionData.cs | 20 ++++++ .../csharp/VA/VA/Services/BotServices.cs | 4 +- .../csharp/VA/VA/Services/BotSettings.cs | 1 + templates/csharp/VA/VA/Startup.cs | 8 ++- templates/csharp/VA/VA/VA.csproj | 2 +- .../csharp/VA/VA/VAProjectTemplate.vstemplate | 8 ++- templates/csharp/VA/VA/appsettings.json | 3 +- 13 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 templates/csharp/VA/VA/Extensions/InvokeActivityExtensions.cs create mode 100644 templates/csharp/VA/VA/Extensions/InvokeResponseExtensions.cs create mode 100644 templates/csharp/VA/VA/Models/SkillCardActionData.cs diff --git a/templates/csharp/VA/VA.Tests/BotTestBase.cs b/templates/csharp/VA/VA.Tests/BotTestBase.cs index 69c1ce46b9..5855dabd28 100644 --- a/templates/csharp/VA/VA.Tests/BotTestBase.cs +++ b/templates/csharp/VA/VA.Tests/BotTestBase.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -16,8 +17,11 @@ using Microsoft.Bot.Solutions.Responses; using Microsoft.Bot.Solutions.Skills.Dialogs; using Microsoft.Bot.Solutions.Testing; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using $ext_safeprojectname$.Bots; using $ext_safeprojectname$.Dialogs; using $ext_safeprojectname$.Models; @@ -53,7 +57,7 @@ protected Templates AllResponsesTemplates [TestInitialize] public virtual void Initialize() { - Services = new ServiceCollection(); + Services = new ServiceCollection().AddLogging(config => config.AddConsole()); Services.AddSingleton(new BotSettings()); Services.AddSingleton(new BotServices() { @@ -131,6 +135,14 @@ public virtual void Initialize() Services.AddSingleton(); Services.AddTransient>(); + // Add MicrosoftAPPId to configuration + var configuration = new Mock(); + var configurationSection = new Mock(); + configurationSection.Setup(a => a.Value).Returns("testvalue"); + configuration.Setup(a => a.GetSection("MicrosoftAppId")).Returns(configurationSection.Object); + // Register configuration + Services.AddSingleton(configuration.Object); + TestUserProfileState = new UserProfileState(); TestUserProfileState.Name = "Bot"; } diff --git a/templates/csharp/VA/VA.Tests/VA.Tests.csproj b/templates/csharp/VA/VA.Tests/VA.Tests.csproj index 95f04798a8..0edde40533 100644 --- a/templates/csharp/VA/VA.Tests/VA.Tests.csproj +++ b/templates/csharp/VA/VA.Tests/VA.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/templates/csharp/VA/VA/Bots/DefaultActivityHandler.cs b/templates/csharp/VA/VA/Bots/DefaultActivityHandler.cs index 63f3e475bb..1ba4ee9f71 100644 --- a/templates/csharp/VA/VA/Bots/DefaultActivityHandler.cs +++ b/templates/csharp/VA/VA/Bots/DefaultActivityHandler.cs @@ -3,17 +3,26 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Dialogs.Choices; +using Microsoft.Bot.Builder.Integration.AspNet.Core.Skills; using Microsoft.Bot.Builder.Teams; using Microsoft.Bot.Connector; +using Microsoft.Bot.Connector.Authentication; using Microsoft.Bot.Schema; +using Microsoft.Bot.Schema.Teams; using Microsoft.Bot.Solutions; using Microsoft.Bot.Solutions.Responses; +using Microsoft.Bot.Solutions.Skills; +using Microsoft.Bot.Solutions.Skills.Models; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using $safeprojectname$.Extensions; using $safeprojectname$.Models; namespace $safeprojectname$.Bots @@ -27,8 +36,13 @@ public class DefaultActivityHandler : TeamsActivityHandler private readonly IStatePropertyAccessor _dialogStateAccessor; private readonly IStatePropertyAccessor _userProfileState; private readonly LocaleTemplateManager _templateManager; + private readonly SkillHttpClient _skillHttpClient; + private readonly SkillsConfiguration _skillsConfig; + private readonly IConfiguration _configuration; + private readonly string _virtualAssistantBotId; + private readonly ILogger _logger; - public DefaultActivityHandler(IServiceProvider serviceProvider, T dialog) + public DefaultActivityHandler(IServiceProvider serviceProvider, ILogger> logger, T dialog) { _dialog = dialog; _dialog.TelemetryClient = serviceProvider.GetService(); @@ -37,6 +51,11 @@ public DefaultActivityHandler(IServiceProvider serviceProvider, T dialog) _dialogStateAccessor = _conversationState.CreateProperty(nameof(DialogState)); _userProfileState = _userState.CreateProperty(nameof(UserProfileState)); _templateManager = serviceProvider.GetService(); + _skillHttpClient = serviceProvider.GetService(); + _skillsConfig = serviceProvider.GetService(); + _configuration = serviceProvider.GetService(); + _virtualAssistantBotId = _configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value; + _logger = logger; } public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default) @@ -104,9 +123,49 @@ protected override async Task OnEventActivityAsync(ITurnContext } } + // Invoked when a "task/fetch" event is received to invoke task module. + protected override async Task OnTeamsTaskModuleFetchAsync(ITurnContext turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken) + { + return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken); + } + + // Invoked when a 'task/submit' invoke activity is received for task module submit actions. + protected override async Task OnTeamsTaskModuleSubmitAsync(ITurnContext turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken) + { + return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken); + } + protected override async Task OnEndOfConversationActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { await _dialog.RunAsync(turnContext, _dialogStateAccessor, cancellationToken); } + + private async Task ProcessTaskModuleInvokeAsync(ITurnContext turnContext, CancellationToken cancellationToken) + { + try + { + // Get Skill From TaskInvoke + var skillId = (turnContext.Activity as Activity).AsInvokeActivity().GetSkillId(_logger); + var skill = _skillsConfig.Skills.Where(s => s.Value.AppId == skillId).FirstOrDefault().Value; + + // Forward request to correct skill + var invokeResponse = await _skillHttpClient.PostActivityAsync(_virtualAssistantBotId, skill, _skillsConfig.SkillHostEndpoint, turnContext.Activity as Activity, cancellationToken).ConfigureAwait(false); + + // Temporary workaround to get correct invokeresponse + // issue: https://github.com/microsoft/botframework-sdk/issues/5929 + var response = new InvokeResponse() + { + Status = invokeResponse.Status, + Body = ((Microsoft.Bot.Builder.InvokeResponse)invokeResponse).Body + }; + + return response.GetTaskModuleResponse(); + } + catch + { + await turnContext.SendActivityAsync(_templateManager.GenerateActivityForLocale("ErrorMessage")); + throw; + } + } } } \ No newline at end of file diff --git a/templates/csharp/VA/VA/Dialogs/MainDialog.cs b/templates/csharp/VA/VA/Dialogs/MainDialog.cs index 26a74f9ee4..5712a911bd 100644 --- a/templates/csharp/VA/VA/Dialogs/MainDialog.cs +++ b/templates/csharp/VA/VA/Dialogs/MainDialog.cs @@ -33,6 +33,7 @@ public class MainDialog : ComponentDialog private readonly LocaleTemplateManager _templateManager; private readonly BotServices _services; + private readonly BotSettings _settings; private readonly OnboardingDialog _onboardingDialog; private readonly SwitchSkillDialog _switchSkillDialog; private readonly SkillsConfiguration _skillsConfig; @@ -44,6 +45,7 @@ public MainDialog( IServiceProvider serviceProvider) : base(nameof(MainDialog)) { + _settings = serviceProvider.GetService(); _services = serviceProvider.GetService(); _templateManager = serviceProvider.GetService(); _skillsConfig = serviceProvider.GetService(); @@ -189,7 +191,8 @@ protected virtual QnAMakerDialog TryCreateQnADialog(string knowledgebaseId, Cogn activeLearningCardTitle: _templateManager.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text, cardNoMatchText: _templateManager.GenerateActivityForLocale("QnaMakerNoMatchText").Text) { - Id = knowledgebaseId + Id = knowledgebaseId, + LogPersonalInformation = _settings.LogPersonalData }; } else diff --git a/templates/csharp/VA/VA/Extensions/InvokeActivityExtensions.cs b/templates/csharp/VA/VA/Extensions/InvokeActivityExtensions.cs new file mode 100644 index 0000000000..8b156b706c --- /dev/null +++ b/templates/csharp/VA/VA/Extensions/InvokeActivityExtensions.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using AdaptiveExpressions; +using Microsoft.Bot.Schema; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using $safeprojectname$.Models; + +namespace $safeprojectname$.Extensions +{ + /// + /// Extension class for getting SkillId from Activity. + /// + public static class InvokeActivityExtensions + { + // Fetches skillId from CardAction data if present + public static string GetSkillId(this IInvokeActivity activity, ILogger logger) + { + if (activity == null) + { + logger.Log(LogLevel.Error, "activity is null from TaskModule"); + throw new ArgumentNullException(nameof(activity)); + } + + if (activity.Value == null) + { + logger.Log(LogLevel.Error, "activity.Value is null from TaskModule"); + throw new ArgumentException("activity.Value is null.", nameof(activity)); + } + + // GetSkillId from Activity Value + var data = JObject.Parse(activity.Value.ToString()).SelectToken("data.data")?.ToObject(); + return data.SkillId ?? throw new ArgumentException("SkillId in TaskModule is null", nameof(SkillCardActionData)); + } + } +} diff --git a/templates/csharp/VA/VA/Extensions/InvokeResponseExtensions.cs b/templates/csharp/VA/VA/Extensions/InvokeResponseExtensions.cs new file mode 100644 index 0000000000..551867c8ab --- /dev/null +++ b/templates/csharp/VA/VA/Extensions/InvokeResponseExtensions.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Schema.Teams; +using Newtonsoft.Json.Linq; + +namespace $safeprojectname$.Extensions +{ + /// + /// InvokeResposneHandler class for returning TaskModuleResponse from InvokeResponse + /// + public static class InvokeResponseExtensions + { + // Converts "InvokeResponse" sent by SkillHttpClient to "TaskModuleResponse" + public static TaskModuleResponse GetTaskModuleResponse(this InvokeResponse invokeResponse) + { + if (invokeResponse == null) + { + throw new ArgumentNullException(nameof(invokeResponse)); + } + + if (invokeResponse.Body != null) + { + return new TaskModuleResponse() + { + Task = GetTask(invokeResponse.Body), + }; + } + + return null; + } + + private static TaskModuleResponseBase GetTask(object invokeResponseBody) + { + var responseBody = JObject.FromObject(invokeResponseBody); + var task = responseBody.GetValue("task"); + string taskType = task.SelectToken("type")?.Value(); + + return taskType switch + { + "continue" => new TaskModuleContinueResponse() + { + Type = taskType, + Value = task.SelectToken("value").ToObject(), + }, + "message" => new TaskModuleMessageResponse() + { + Type = taskType, + Value = task.SelectToken("value").ToString(), + }, + _ => null, + }; + } + } +} \ No newline at end of file diff --git a/templates/csharp/VA/VA/Models/SkillCardActionData.cs b/templates/csharp/VA/VA/Models/SkillCardActionData.cs new file mode 100644 index 0000000000..e03451c760 --- /dev/null +++ b/templates/csharp/VA/VA/Models/SkillCardActionData.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Newtonsoft.Json; + +namespace $safeprojectname$.Models +{ + /// + /// Skill Card action data should contain skillName parameter + /// This class is used to deserialize it and get skillName. + /// + /// + /// SkillName. + /// + public class SkillCardActionData + { + [JsonProperty("SkillId")] + public string SkillId { get; set; } + } +} diff --git a/templates/csharp/VA/VA/Services/BotServices.cs b/templates/csharp/VA/VA/Services/BotServices.cs index ff2046a34f..cbcd6648dd 100644 --- a/templates/csharp/VA/VA/Services/BotServices.cs +++ b/templates/csharp/VA/VA/Services/BotServices.cs @@ -36,7 +36,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client) luisOptions = new LuisRecognizerOptionsV3(dispatchApp) { TelemetryClient = telemetryClient, - LogPersonalInformation = true, + LogPersonalInformation = settings.LogPersonalData, }; set.DispatchService = new LuisRecognizer(luisOptions); } @@ -49,7 +49,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client) luisOptions = new LuisRecognizerOptionsV3(luisApp) { TelemetryClient = telemetryClient, - LogPersonalInformation = true, + LogPersonalInformation = settings.LogPersonalData, }; set.LuisServices.Add(model.Id, new LuisRecognizer(luisOptions)); } diff --git a/templates/csharp/VA/VA/Services/BotSettings.cs b/templates/csharp/VA/VA/Services/BotSettings.cs index 58d475f449..a1ce832985 100644 --- a/templates/csharp/VA/VA/Services/BotSettings.cs +++ b/templates/csharp/VA/VA/Services/BotSettings.cs @@ -9,5 +9,6 @@ namespace $safeprojectname$.Services public class BotSettings : BotSettingsBase { public TokenExchangeConfig TokenExchangeConfig { get; set; } + public bool LogPersonalData { get; set; } } } \ No newline at end of file diff --git a/templates/csharp/VA/VA/Startup.cs b/templates/csharp/VA/VA/Startup.cs index f605ad1586..1a8085d04d 100644 --- a/templates/csharp/VA/VA/Startup.cs +++ b/templates/csharp/VA/VA/Startup.cs @@ -58,7 +58,10 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(Configuration); // Load settings - var settings = new BotSettings(); + var settings = new BotSettings() + { + LogPersonalData = Configuration.GetSection("logPersonalInfo")?.Value.ToLower() == "true" + }; Configuration.Bind(settings); services.AddSingleton(settings); @@ -82,7 +85,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + + services.AddSingleton(s => new TelemetryLoggerMiddleware(s.GetService(), settings.LogPersonalData)); // Configure bot services services.AddSingleton(); diff --git a/templates/csharp/VA/VA/VA.csproj b/templates/csharp/VA/VA/VA.csproj index 39c07e298b..98d3af7818 100644 --- a/templates/csharp/VA/VA/VA.csproj +++ b/templates/csharp/VA/VA/VA.csproj @@ -17,7 +17,7 @@ - + diff --git a/templates/csharp/VA/VA/VAProjectTemplate.vstemplate b/templates/csharp/VA/VA/VAProjectTemplate.vstemplate index efa7ee432e..ee4255d442 100644 --- a/templates/csharp/VA/VA/VAProjectTemplate.vstemplate +++ b/templates/csharp/VA/VA/VAProjectTemplate.vstemplate @@ -27,9 +27,6 @@ DefaultAdapter.cs - - AllowedCallersClaimsValidator.cs - DefaultActivityHandler.cs @@ -101,7 +98,12 @@ MainDialog.cs OnboardingDialog.cs + + InvokeActivityExtensions.cs + InvokeResponseExtensions.cs + + SkillCardActionData.cs StateProperties.cs UserProfileState.cs diff --git a/templates/csharp/VA/VA/appsettings.json b/templates/csharp/VA/VA/appsettings.json index 1b67a8b836..044d468783 100644 --- a/templates/csharp/VA/VA/appsettings.json +++ b/templates/csharp/VA/VA/appsettings.json @@ -21,5 +21,6 @@ }, "contentModerator": { "key": "" - } + }, + "logPersonalInfo": true } \ No newline at end of file From 775f62b3a285aeb53b84065c7bcf88cd37efb656 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 10 Jun 2021 15:57:23 -0300 Subject: [PATCH 2/2] Update Skill template --- .../csharp/Skill/Skill/Services/BotServices.cs | 4 ++-- .../csharp/Skill/Skill/Services/BotSettings.cs | 1 + .../Skill/Skill/SkillProjectTemplate.vstemplate | 3 --- templates/csharp/Skill/Skill/Startup.cs | 15 ++++++++++++--- templates/csharp/Skill/Skill/appsettings.json | 3 ++- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/templates/csharp/Skill/Skill/Services/BotServices.cs b/templates/csharp/Skill/Skill/Services/BotServices.cs index 70d24285b0..95ceab0471 100644 --- a/templates/csharp/Skill/Skill/Services/BotServices.cs +++ b/templates/csharp/Skill/Skill/Services/BotServices.cs @@ -36,7 +36,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client) luisOptions = new LuisRecognizerOptionsV3(dispatchApp) { TelemetryClient = telemetryClient, - LogPersonalInformation = true, + LogPersonalInformation = settings.LogPersonalData, }; set.DispatchService = new LuisRecognizer(luisOptions); } @@ -49,7 +49,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client) luisOptions = new LuisRecognizerOptionsV3(luisApp) { TelemetryClient = telemetryClient, - LogPersonalInformation = true, + LogPersonalInformation = settings.LogPersonalData, }; set.LuisServices.Add(model.Id, new LuisRecognizer(luisOptions)); } diff --git a/templates/csharp/Skill/Skill/Services/BotSettings.cs b/templates/csharp/Skill/Skill/Services/BotSettings.cs index f39f7febe4..52f1ee3b3d 100644 --- a/templates/csharp/Skill/Skill/Services/BotSettings.cs +++ b/templates/csharp/Skill/Skill/Services/BotSettings.cs @@ -7,5 +7,6 @@ namespace $safeprojectname$.Services { public class BotSettings : BotSettingsBase { + public bool LogPersonalData { get; set; } } } \ No newline at end of file diff --git a/templates/csharp/Skill/Skill/SkillProjectTemplate.vstemplate b/templates/csharp/Skill/Skill/SkillProjectTemplate.vstemplate index 8d94767844..dff9760beb 100644 --- a/templates/csharp/Skill/Skill/SkillProjectTemplate.vstemplate +++ b/templates/csharp/Skill/Skill/SkillProjectTemplate.vstemplate @@ -31,9 +31,6 @@ DefaultAdapter.cs - - AllowedCallersClaimsValidator.cs - DefaultActivityHandler.cs diff --git a/templates/csharp/Skill/Skill/Startup.cs b/templates/csharp/Skill/Skill/Startup.cs index 0f2c82fc8d..f73aefafc1 100644 --- a/templates/csharp/Skill/Skill/Startup.cs +++ b/templates/csharp/Skill/Skill/Startup.cs @@ -62,7 +62,10 @@ public void ConfigureServices(IServiceCollection services) }); // Load settings - var settings = new BotSettings(); + var settings = new BotSettings() + { + LogPersonalData = Configuration.GetSection("logPersonalInfo")?.Value.ToLower() == "true" + }; Configuration.Bind(settings); services.AddSingleton(settings); services.AddSingleton(settings); @@ -85,8 +88,14 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - + if (settings.LogPersonalData) + { + services.AddSingleton(s => new TelemetryLoggerMiddleware(s.GetService(), true)); + } + else + { + services.AddSingleton(); + } // Configure bot services services.AddSingleton(); diff --git a/templates/csharp/Skill/Skill/appsettings.json b/templates/csharp/Skill/Skill/appsettings.json index a0e4aef284..4e926f11dc 100644 --- a/templates/csharp/Skill/Skill/appsettings.json +++ b/templates/csharp/Skill/Skill/appsettings.json @@ -17,5 +17,6 @@ "containerId": "botstate-collection", "databaseId": "botstate-db" }, - "properties": {} + "properties": {}, + "logPersonalInfo": true }