diff --git a/.github/workflows/build-complete-samples.yml b/.github/workflows/build-complete-samples.yml index 9e357bec34..906143cdec 100644 --- a/.github/workflows/build-complete-samples.yml +++ b/.github/workflows/build-complete-samples.yml @@ -460,9 +460,9 @@ jobs: name: 'bot-configuration-app' version: '6.0.x' - - project_path: 'samples/bot-configuration-app-auth/csharp/Bot configuration/Bot Configuration.csproj' + - project_path: 'samples/bot-configuration-app-auth/csharp/Bot configuration/Bot configuration.csproj' name: 'bot-configuration-app-auth' - version: '6.0.x' + version: '10.0.x' - project_path: 'samples/app-HR-talent/csharp/src/TeamsTalentMgmtAppV6.csproj' name: 'app-HR-talent' diff --git a/samples/bot-configuration-app-auth/csharp/Bot Configuration.sln b/samples/bot-configuration-app-auth/csharp/Bot Configuration.sln deleted file mode 100644 index 0033c74f20..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot Configuration.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34302.85 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot Configuration", "Bot configuration\Bot Configuration.csproj", "{783D6E6F-7339-4D74-89D4-B240496CC7A3}" -EndProject -Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "M365Agent", "M365Agent\M365Agent.ttkproj", "{8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5C136CED-CFA6-4839-A70F-F8FAB5EF59CC}" - ProjectSection(SolutionItems) = preProject - Bot Configuration.slnLaunch.user = Bot Configuration.slnLaunch.user - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {783D6E6F-7339-4D74-89D4-B240496CC7A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {783D6E6F-7339-4D74-89D4-B240496CC7A3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {783D6E6F-7339-4D74-89D4-B240496CC7A3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {783D6E6F-7339-4D74-89D4-B240496CC7A3}.Release|Any CPU.Build.0 = Release|Any CPU - {8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A5D16E9-1CAF-42D6-8400-75AE6088E9A5}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {C0264D40-8A26-4CAF-9DE9-0CFF497234D8} - EndGlobalSection -EndGlobal diff --git a/samples/bot-configuration-app-auth/csharp/Bot Configuration.slnLaunch.user b/samples/bot-configuration-app-auth/csharp/Bot Configuration.slnLaunch.user index 541f4d3174..0e0a746c40 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot Configuration.slnLaunch.user +++ b/samples/bot-configuration-app-auth/csharp/Bot Configuration.slnLaunch.user @@ -1,31 +1,52 @@ [ { - "Name": "Microsoft Teams (browser)", + "Name": "Microsoft 365 Agents Playground (browser)", "Projects": [ { - "Path": "Bot configuration\\Bot Configuration.csproj", - "Action": "Start", - "DebugTarget": "Start Project" + "Path": "M365Agent\\M365Agent.atkproj", + "Name": "M365Agent\\M365Agent.atkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft 365 Agents Playground (browser)" }, { - "Path": "M365Agent\\M365Agent.ttkproj", - "Action": "StartWithoutDebugging", - "DebugTarget": "Microsoft Teams (browser)" + "Path": "Bot configuration\\Bot configuration.csproj", + "Name": "Bot configuration\\Bot configuration.csproj", + "Action": "Start", + "DebugTarget": "Microsoft 365 Agents Playground" } ] }, { - "Name": "Microsoft Teams (browser) (skip update app)", + "Name": "Microsoft Teams (browser)", "Projects": [ { - "Path": "Bot configuration\\Bot Configuration.csproj", + "Path": "M365Agent\\M365Agent.atkproj", + "Name": "M365Agent\\M365Agent.atkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (browser)" + }, + { + "Path": "Bot configuration\\Bot configuration.csproj", + "Name": "Bot configuration\\Bot configuration.csproj", "Action": "Start", "DebugTarget": "Start Project" - }, + } + ] + }, + { + "Name": "Microsoft Teams (browser) (skip update app)", + "Projects": [ { - "Path": "M365Agent\\M365Agent.ttkproj", + "Path": "M365Agent\\M365Agent.atkproj", + "Name": "M365Agent\\M365Agent.atkproj", "Action": "StartWithoutDebugging", "DebugTarget": "Microsoft Teams (browser) (skip update app)" + }, + { + "Path": "Bot configuration\\Bot configuration.csproj", + "Name": "Bot configuration\\Bot configuration.csproj", + "Action": "Start", + "DebugTarget": "Start Project" } ] } diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration.slnx b/samples/bot-configuration-app-auth/csharp/Bot configuration.slnx new file mode 100644 index 0000000000..504ac2d8d4 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration.slnx @@ -0,0 +1,6 @@ + + + + + + diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/.gitignore b/samples/bot-configuration-app-auth/csharp/Bot configuration/.gitignore index 7466c01f9c..77c7154916 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/.gitignore +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/.gitignore @@ -5,6 +5,7 @@ env/.env.*.user env/.env.local appsettings.Development.json .deployment +appsettings.Playground.json # User-specific files *.user @@ -22,4 +23,8 @@ bld/ [Ll]og/ # Notification local store -.notification.localstore.json \ No newline at end of file +.notification.localstore.json +.notification.playgroundstore.json + +# devTools +devTools/ \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/AdapterWithErrorHandler.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/AdapterWithErrorHandler.cs deleted file mode 100644 index c924c6cc78..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/AdapterWithErrorHandler.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// -// Generated with Bot Builder V4 SDK Template for Visual Studio CoreBot v4.6.2 - -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Integration.AspNet.Core; -using Microsoft.Bot.Builder.TraceExtensions; -using Microsoft.Bot.Connector.Authentication; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Teams.Samples.HelloWorld.Web -{ - /// - /// AdapterWithErrorHandler handles errors during bot execution. - /// - public class AdapterWithErrorHandler : CloudAdapter - { - /// - /// Initializes a new instance of the class. - /// - /// The bot framework authentication. - /// The logger. - public AdapterWithErrorHandler(BotFrameworkAuthentication botFrameworkAuthentication, ILogger logger) - : base(botFrameworkAuthentication, logger) - { - OnTurnError = async (turnContext, exception) => - { - // Log any leaked exception from the application. - logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); - - // Uncomment the line below for local debugging. - // await turnContext.SendActivityAsync($"Sorry, it looks like something went wrong. Exception Caught: {exception.Message}"); - - // Send a trace activity, which will be displayed in the Bot Framework Emulator - await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); - }; - } - } -} diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Bot Configuration.csproj b/samples/bot-configuration-app-auth/csharp/Bot configuration/Bot Configuration.csproj index e65308dbe5..81958d0257 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Bot Configuration.csproj +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Bot Configuration.csproj @@ -1,26 +1,30 @@ - + - net6.0 - latest + net10.0 + enable + enable - - + + + + + + - - - - - - - - - Always + + + PreserveNewest + None + + + + PreserveNewest + None - \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Bots/TeamsBot.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Bots/TeamsBot.cs deleted file mode 100644 index b6288c05fe..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Bots/TeamsBot.cs +++ /dev/null @@ -1,144 +0,0 @@ -using AdaptiveCards; -using Bogus.DataSets; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Teams; -using Microsoft.Bot.Schema; -using Microsoft.Bot.Schema.Teams; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Net.Http; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using System.IO; - -namespace Botconfiguration.Bots -{ - /// - /// TeamsBot class handles bot activities for Microsoft Teams. - /// - public class TeamsBot : TeamsActivityHandler - { - private string _chosenFlow = string.Empty; - - /// - /// Handles the event when members are added to the channel. - /// - /// List of members added. - /// Turn context. - /// Cancellation token. - protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken) - { - const string imagePath = "Images/configbutton.png"; - var imageData = Convert.ToBase64String(await File.ReadAllBytesAsync(imagePath)); - - var adaptiveCardJson = $@" - {{ - ""$schema"": ""http://adaptivecards.io/schemas/adaptive-card.json"", - ""type"": ""AdaptiveCard"", - ""version"": ""1.0"", - ""body"": [ - {{ - ""type"": ""TextBlock"", - ""text"": ""Hello and welcome! With this sample, you can experience the functionality of bot configuration. To access Bot configuration, click on the settings button in the bot description card."", - ""wrap"": true, - ""size"": ""large"", - ""weight"": ""bolder"" - }}, - {{ - ""type"": ""Image"", - ""url"": ""data:image/png;base64,{imageData}"", - ""size"": ""auto"" - }} - ], - ""fallbackText"": ""This card requires Adaptive Card support."" - }}"; - - var attachment = new Attachment - { - ContentType = AdaptiveCard.ContentType, - Content = JsonConvert.DeserializeObject(adaptiveCardJson) - }; - - var reply = MessageFactory.Attachment(attachment); - await turnContext.SendActivityAsync(reply, cancellationToken); - } - - /// - /// Handles the event when a message activity is received. - /// - /// Turn context. - /// Cancellation token. - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - var activity = turnContext.Activity; - if (!string.IsNullOrEmpty(activity.Text)) - { - var text = activity.Text.ToLower().Trim(); - if (text == "chosen flow" || text == "typeahead search adaptive card chosen flow") - { - await turnContext.SendActivityAsync($"Bot configured for {_chosenFlow} flow", cancellationToken: cancellationToken); - } - } - else if (activity.Value != null) - { - await turnContext.SendActivityAsync($"Selected option is: {activity.Value}", cancellationToken: cancellationToken); - } - } - - /// - /// Handles the event when a configuration fetch is requested. - /// - /// Turn context. - /// Configuration data. - /// Cancellation token. - /// Configuration response. - protected override Task OnTeamsConfigFetchAsync(ITurnContext turnContext, JObject configData, CancellationToken cancellationToken) - { - var response = new ConfigResponse - { - Config = new BotConfigAuth - { - SuggestedActions = new SuggestedActions - { - Actions = new List - { - new CardAction - { - Type = ActionTypes.OpenUrl, - Title = "Sign in to this app", - Value = "https://example.com/auth" - } - } - }, - Type = "auth" - } - }; - return Task.FromResult(response); - } - - /// - /// Handles the event when a configuration submit is requested. - /// - /// Turn context. - /// Configuration data. - /// Cancellation token. - /// Configuration response. - protected override Task OnTeamsConfigSubmitAsync(ITurnContext turnContext, JObject configData, CancellationToken cancellationToken) - { - var response = new ConfigResponse - { - Config = new TaskModuleMessageResponse - { - Type = "message", - Value = "You have chosen to finish setting up bot" - } - }; - - return Task.FromResult(response); - } - } -} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Config.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Config.cs new file mode 100644 index 0000000000..9f79e2b2b3 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Config.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Bot_configuration +{ + public class ConfigOptions + { + public TeamsConfigOptions Teams { get; set; } + } + + public class TeamsConfigOptions + { + public string ClientId { get; set; } + public string ClientSecret { get; set; } + public string TenantId { get; set; } + } +} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/BotController.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/BotController.cs deleted file mode 100644 index 80da0b44fd..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/BotController.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// -// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.6.2 - -using Microsoft.AspNetCore.Mvc; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Integration.AspNet.Core; -using System.Threading.Tasks; - -namespace Botconfiguration.Controllers -{ - // This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot - // implementation at runtime. Multiple different IBot implementations running at different endpoints can be - // achieved by specifying a more specific type for the bot constructor argument. - [Route("api/messages")] - [ApiController] - public class BotController : ControllerBase - { - private readonly CloudAdapter Adapter; - private readonly IBot Bot; - - public BotController(CloudAdapter adapter, IBot bot) - { - Adapter = adapter; - Bot = bot; - } - - [HttpPost] - public async Task PostAsync() - { - // Delegate the processing of the HTTP POST to the adapter. - // The adapter will invoke the bot. - await Adapter.ProcessAsync(Request, Response, Bot); - } - } -} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/Controller.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/Controller.cs new file mode 100644 index 0000000000..9f4eebbc26 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/Controller.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Teams.Api.Activities; +using Microsoft.Teams.Apps; +using Microsoft.Teams.Apps.Activities; +using Microsoft.Teams.Apps.Activities.Invokes; +using Microsoft.Teams.Apps.Annotations; +using Microsoft.Teams.Cards; +using System.Text.Json; + +namespace Bot_configuration.Controllers +{ + /// + /// Teams SDK v2 Controller for Bot Configuration Sample + /// Demonstrates bot configuration through settings button (config invoke activities) + /// + [TeamsController] + public class Controller + { + private static string _chosenFlow = string.Empty; + + /// + /// Handles conversation members added event + /// Sends welcome message with configuration instructions + /// + [Conversation.MembersAdded] + public async Task OnMembersAdded([Context] ConversationUpdateActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log) + { + const string imagePath = "Images/configbutton.png"; + string imageData = string.Empty; + if (File.Exists(imagePath)) + { + imageData = Convert.ToBase64String(File.ReadAllBytes(imagePath)); + } + var card = new Microsoft.Teams.Cards.AdaptiveCard + { + Body = new List + { + new TextBlock("Hello and welcome! With this sample, you can experience the functionality of bot configuration. To access Bot configuration, click on the settings button in the bot description card.") + { + Wrap = true, + Size = TextSize.Large, + Weight = TextWeight.Bolder + } + } + }; + if (!string.IsNullOrEmpty(imageData)) + { + card.Body.Add(new Image($"data:image/png;base64,{imageData}")); + } + await client.Send(card); + } + + /// + /// Handles incoming messages + /// + [Message] + public async Task OnMessage([Context] MessageActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log) + { + if (!string.IsNullOrEmpty(activity.Text)) + { + var text = activity.Text.ToLower().Trim(); + if (text == "chosen flow" || text.Contains("chosen flow")) + { + var response = string.IsNullOrEmpty(_chosenFlow) + ? "No flow has been configured yet. Please use the settings button to configure the bot." + : $"Bot configured for {_chosenFlow} flow"; + + await client.Send(response); + } + else + { + await client.Send($"You said: '{activity.Text}'\n\nTry sending 'chosen flow' to check configuration."); + } + } + else if (activity.Value != null) + { + await client.Send($"Selected option is: {activity.Value}"); + } + } + + /// + /// Handles config/fetch invoke - Shows auth dialog when settings button is clicked + /// Replaces OnTeamsConfigFetchAsync from Bot Builder SDK + /// + [Invoke("config/fetch")] + public object OnConfigFetch([Context] InvokeActivity activity, [Context] Microsoft.Teams.Common.Logging.ILogger log) + { + return new + { + config = new + { + type = "auth", + suggestedActions = new + { + actions = new[] + { + new + { + type = "openUrl", + title = "Sign in to this app", + value = "https://example.com/auth" + } + } + } + } + }; + } + + /// + /// Handles config/submit invoke - Processes configuration submission + /// Replaces OnTeamsConfigSubmitAsync from Bot Builder SDK + /// + [Invoke("config/submit")] + public async Task OnConfigSubmit([Context] InvokeActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log) + { + try + { + if (activity.Value != null) + { + var jsonString = JsonSerializer.Serialize(activity.Value); + var valueElement = JsonSerializer.Deserialize(jsonString); + if (valueElement.TryGetProperty("flow", out var flowProperty)) + { + _chosenFlow = flowProperty.GetString() ?? string.Empty; + } + } + await client.Send("✅ You have chosen to finish setting up bot"); + return new + { + config = new + { + type = "message", + value = "You have chosen to finish setting up bot" + } + }; + } + catch (Exception ex) + { + log.Error($"Error processing configuration: {ex.Message}"); + return new + { + config = new + { + type = "message", + value = "An error occurred while saving the configuration." + } + }; + } + } + } +} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/HomeController.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/HomeController.cs index 3281617350..5c786c45cb 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/HomeController.cs +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Controllers/HomeController.cs @@ -1,15 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + using Microsoft.AspNetCore.Mvc; -namespace Microsoft.Teams.Samples.HelloWorld.Web.Controllers +namespace Bot_configuration.Controllers { - public class HomeController : Controller + /// + /// HomeController serves the home page for the bot web application + /// + public class HomeController : Microsoft.AspNetCore.Mvc.Controller { [Route("")] - public ActionResult Index() + [Route("Home")] + [Route("Home/Index")] + public IActionResult Index() { return View(); } diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Program.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Program.cs index c45cf8e115..67fe08093c 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Program.cs +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Program.cs @@ -1,38 +1,37 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// -// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.6.2 - -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace Microsoft.Teams.Samples.HelloWorld.Web -{ - /// - /// The Program class is the entry point of the application. - /// - public class Program - { - /// - /// The main entry point of the application. - /// - /// The command-line arguments. - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - /// - /// Creates the host builder. - /// - /// The command-line arguments. - /// The configured host builder. - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } -} + +using Bot_configuration; +using Bot_configuration.Controllers; +using Azure.Core; +using Azure.Identity; +using Microsoft.Teams.Api.Auth; +using Microsoft.Teams.Apps; +using Microsoft.Teams.Apps.Extensions; +using Microsoft.Teams.Common.Http; +using Microsoft.Teams.Plugins.AspNetCore.Extensions; + +// Create web application builder and load configuration +var builder = WebApplication.CreateBuilder(args); +var config = builder.Configuration.Get(); + +// Create Teams app builder +var appBuilder = App.Builder(); + +// Register controller and configure Teams services +builder.Services.AddControllersWithViews(); +builder.Services.AddSingleton(); +builder.AddTeams(appBuilder); + +// Build and run the application +var app = builder.Build(); + +app.UseStaticFiles(); +app.UseRouting(); + +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.UseTeams(); +app.Run(); \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Properties/launchSettings.json b/samples/bot-configuration-app-auth/csharp/Bot configuration/Properties/launchSettings.json index ff9d8fe153..921e10d3e8 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Properties/launchSettings.json +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/Properties/launchSettings.json @@ -1,13 +1,26 @@ -{ +{ "profiles": { + // Debug project within Microsoft 365 Agents Playground + "Microsoft 365 Agents Playground": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3978", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Playground", + "TEAMSFX_NOTIFICATION_STORE_FILENAME": ".notification.playgroundstore.json", + "UPDATE_TEAMS_APP": "false" + }, + "hotReloadProfile": "aspnetcore" + }, + // Debug project within Teams "Start Project": { "commandName": "Project", "dotnetRunMessages": true, - "applicationUrl": "https://localhost:7130;http://localhost:5130", + "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "hotReloadProfile": "aspnetcore" - } + }, } } \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/Startup.cs b/samples/bot-configuration-app-auth/csharp/Bot configuration/Startup.cs deleted file mode 100644 index 84c44af18c..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/Startup.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// -// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.6.2 - -using Botconfiguration.Bots; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Localization; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Integration.AspNet.Core; -using Microsoft.Bot.Connector.Authentication; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using System.Globalization; - -namespace Microsoft.Teams.Samples.HelloWorld.Web -{ - /// - /// The Startup class configures services and the app's request pipeline. - /// - public class Startup - { - /// - /// Initializes a new instance of the class. - /// - /// The configuration. - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - /// - /// Gets the configuration. - /// - public IConfiguration Configuration { get; } - - /// - /// This method gets called by the runtime. Use this method to add services to the container. - /// - /// The service collection. - public void ConfigureServices(IServiceCollection services) - { - services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; }); - services.Configure(options => - { - var culturesSupported = new[] - { - new CultureInfo("en-US"), - new CultureInfo("fr-CA"), - new CultureInfo("hi-IN"), - new CultureInfo("es-MX") - }; - options.DefaultRequestCulture = new RequestCulture("en-US"); - options.SupportedCultures = culturesSupported; - options.SupportedUICultures = culturesSupported; - options.FallBackToParentCultures = false; - }); - - services.AddControllers(); - services.AddMvc() - .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, - opts => { opts.ResourcesPath = "Resources"; }) - .AddDataAnnotationsLocalization(); - - // Create the Bot Framework Authentication to be used with the Bot Adapter. - services.AddSingleton(); - - // Create the Cloud Adapter with error handling enabled. - services.AddSingleton(); - - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. - services.AddTransient(); - } - - /// - /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - /// - /// The application builder. - /// The web host environment. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseHsts(); - } - app.UseDefaultFiles(); - app.UseStaticFiles(); - app.UseWebSockets(); - - var locOptions = app.ApplicationServices.GetService>(); - app.UseRequestLocalization(locOptions.Value); - - // Runs matching. An endpoint is selected and set on the HttpContext if a match is found. - app.UseRouting(); - - app.UseEndpoints(endpoints => - { - // Mapping of endpoints goes here: - endpoints.MapControllers(); - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - - //app.UseHttpsRedirection(); - } - } -} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Development.json b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Development.json index b49abfc201..8dadbe2c24 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Development.json +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Development.json @@ -1,9 +1,18 @@ { - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } - } + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + }, + "Microsoft.Teams": { + "Enable": "*", + "Level": "debug" + } + }, + "AllowedHosts": "*", + "Teams": { + "ClientId": "", + "ClientSecret": "", + "TenantId": "" + } +} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Playground.json b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Playground.json new file mode 100644 index 0000000000..5981a18df5 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.Playground.json @@ -0,0 +1,18 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + }, + "Microsoft.Teams": { + "Enable": "*", + "Level": "debug" + } + }, + "AllowedHosts": "*", + "Teams": { + "ClientId": "", + "ClientSecret": "", + "TenantId": "" + } +} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.json b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.json index 94f22e7cac..41145a092b 100644 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.json +++ b/samples/bot-configuration-app-auth/csharp/Bot configuration/appsettings.json @@ -1,6 +1,17 @@ { - "MicrosoftAppId": "", - "MicrosoftAppPassword": "", - "MicrosoftAppType": "", - "MicrosoftAppTenantId": "" + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + }, + "Microsoft.Teams": { + "Enable": "*", + "Level": "debug" + } + }, + "AllowedHosts": "*", + "Teams": { + "ClientId": "", + "ClientSecret": "" + } } \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/favicon.ico b/samples/bot-configuration-app-auth/csharp/Bot configuration/favicon.ico deleted file mode 100644 index a3a799985c..0000000000 Binary files a/samples/bot-configuration-app-auth/csharp/Bot configuration/favicon.ico and /dev/null differ diff --git a/samples/bot-configuration-app-auth/csharp/Bot configuration/packages.config b/samples/bot-configuration-app-auth/csharp/Bot configuration/packages.config deleted file mode 100644 index 9343961634..0000000000 --- a/samples/bot-configuration-app-auth/csharp/Bot configuration/packages.config +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/.gitignore b/samples/bot-configuration-app-auth/csharp/M365Agent/.gitignore new file mode 100644 index 0000000000..c5cae9258c --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/.gitignore @@ -0,0 +1,10 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.atkproj b/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.atkproj new file mode 100644 index 0000000000..124eb75046 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.atkproj @@ -0,0 +1,9 @@ + + + + b069b3bd-f6bc-cc40-82ab-3fcc2ea50fdf + + + + + \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.ttkproj b/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.ttkproj deleted file mode 100644 index baf1922d65..0000000000 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/M365Agent.ttkproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - 8a5d16e9-1caf-42d6-8400-75ae6088e9a5 - - - - - - - - - - \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/aad.manifest.json b/samples/bot-configuration-app-auth/csharp/M365Agent/aad.manifest.json index 48aeaf0cfc..4cd02d6613 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/aad.manifest.json +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/aad.manifest.json @@ -1,6 +1,6 @@ { - "id": "${{AAD_APP_OBJECT_ID}}", - "appId": "${{AAD_APP_CLIENT_ID}}", + "id": "${{BOT_OBJECT_ID}}", + "appId": "${{BOT_ID}}", "name": "bot-configuration-app-auth-aad", "accessTokenAcceptedVersion": 2, "signInAudience": "AzureADMyOrg", diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/color.png b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/color.png index b8cf81afbe..01aa37e347 100644 Binary files a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/color.png and b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/color.png differ diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/manifest.json b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/manifest.json index 4ae26c6294..8795b93d98 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/manifest.json +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/manifest.json @@ -25,7 +25,7 @@ "accentColor": "#60A18E", "bots": [ { - "botId": "${{AAD_APP_CLIENT_ID}}", + "botId": "${{BOT_ID}}", "needsChannelSelector": false, "scopes": [ "personal", diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/outline.png b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/outline.png index 2c3bf6fa65..f7a4c86447 100644 Binary files a/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/outline.png and b/samples/bot-configuration-app-auth/csharp/M365Agent/appPackage/outline.png differ diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/build/aad.manifest.local.json b/samples/bot-configuration-app-auth/csharp/M365Agent/build/aad.manifest.local.json deleted file mode 100644 index 97be775c31..0000000000 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/build/aad.manifest.local.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "id": "58ba9868-18e6-41ca-8529-495e3ded97e9", - "appId": "56516855-807f-487e-b7cf-7dbfcc437db4", - "name": "bot-configuration-app-auth-aad", - "accessTokenAcceptedVersion": 2, - "signInAudience": "AzureADMyOrg", - "oauth2AllowIdTokenImplicitFlow": true, - "oauth2AllowImplicitFlow": true, - "optionalClaims": { - "idToken": [], - "accessToken": [ - { - "name": "idtyp", - "source": null, - "essential": false, - "additionalProperties": [] - } - ], - "saml2Token": [] - }, - "requiredResourceAccess": [ - { - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { - "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", - "type": "Scope" - } - ] - } - ] -} \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.dev b/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.dev new file mode 100644 index 0000000000..df4f9da508 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.dev @@ -0,0 +1,15 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups. +AZURE_SUBSCRIPTION_ID= +AZURE_RESOURCE_GROUP_NAME= +RESOURCE_SUFFIX= + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_AZURE_APP_SERVICE_RESOURCE_ID= \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.local b/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.local index 0543fc6b40..86dfacc35a 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.local +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/env/.env.local @@ -4,20 +4,11 @@ TEAMSFX_ENV=local APP_NAME_SUFFIX=local -# Generated during provision, you can also add your own variables. +# Generated during provision, you can also add your own variables. BOT_ID= TEAMS_APP_ID= -RESOURCE_SUFFIX= -AZURE_SUBSCRIPTION_ID= -AZURE_RESOURCE_GROUP_NAME= -AAD_APP_CLIENT_ID= -AAD_APP_OBJECT_ID= -AAD_APP_TENANT_ID= -AAD_APP_OAUTH_AUTHORITY= -AAD_APP_OAUTH_AUTHORITY_HOST= TEAMS_APP_TENANT_ID= -MICROSOFT_APP_TYPE= -MICROSOFT_APP_TENANT_ID= +BOT_OBJECT_ID= TEAMSFX_M365_USER_NAME= BOT_ENDPOINT= diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.bicep b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.bicep index c3ce051b3d..658e412a21 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.bicep +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.bicep @@ -3,42 +3,84 @@ @description('Used to generate names for all resources in this file') param resourceBaseName string -@description('Required when create Azure Bot service') -param botAadAppClientId string - -param botAppDomain string +param webAppSKU string @maxLength(42) param botDisplayName string -param botServiceName string = resourceBaseName -param botServiceSku string = 'F0' -param microsoftAppType string -param microsoftAppTenantId string +param serverfarmsName string = resourceBaseName +param webAppName string = resourceBaseName +param identityName string = resourceBaseName +param location string = resourceGroup().location -// Register your web service as a bot with the Bot Framework -resource botService 'Microsoft.BotService/botServices@2021-03-01' = { - kind: 'azurebot' - location: 'global' - name: botServiceName - properties: { - displayName: botDisplayName - endpoint: 'https://${botAppDomain}/api/messages' - msaAppId: botAadAppClientId - msaAppType: microsoftAppType - msaAppTenantId: microsoftAppType == 'SingleTenant' ? microsoftAppTenantId : '' - } +resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + location: location + name: identityName +} + +// Compute resources for your Web App +resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = { + kind: 'app' + location: location + name: serverfarmsName sku: { - name: botServiceSku + name: webAppSKU } } -// Connect the bot service to Microsoft Teams -resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { - parent: botService - location: 'global' - name: 'MsTeamsChannel' +// Web App that hosts your bot +resource webApp 'Microsoft.Web/sites@2021-02-01' = { + kind: 'app' + location: location + name: webAppName properties: { - channelName: 'MsTeamsChannel' + serverFarmId: serverfarm.id + httpsOnly: true + siteConfig: { + appSettings: [ + { + name: 'WEBSITE_RUN_FROM_PACKAGE' + value: '1' + } + { + name: 'Teams__ClientId' + value: identity.properties.clientId + } + { + name: 'Teams__TenantId' + value: identity.properties.tenantId + } + { + name: 'Teams__BotType' + value: 'UserAssignedMsi' + } + ] + ftpsState: 'FtpsOnly' + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity.id}': {} + } + } +} + +// Register your web service as a bot with the Bot Framework +module azureBotRegistration './botRegistration/azurebot.bicep' = { + name: 'Azure-Bot-registration' + params: { + resourceBaseName: resourceBaseName + identityClientId: identity.properties.clientId + identityResourceId: identity.id + identityTenantId: identity.properties.tenantId + botAppDomain: webApp.properties.defaultHostName + botDisplayName: botDisplayName } } + +// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details. +output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id +output BOT_DOMAIN string = webApp.properties.defaultHostName +output BOT_ID string = identity.properties.clientId +output BOT_TENANT_ID string = identity.properties.tenantId diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.parameters.json b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.parameters.json index 90c4fd5bfc..3434c4a7ce 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.parameters.json +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/azure.parameters.json @@ -1,24 +1,15 @@ { - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "resourceBaseName": { - "value": "bot${{RESOURCE_SUFFIX}}" - }, - "botAadAppClientId": { - "value": "${{AAD_APP_CLIENT_ID}}" - }, - "botAppDomain": { - "value": "${{BOT_DOMAIN}}" - }, - "botDisplayName": { - "value": "bot-configuration-app-auth" - }, - "microsoftAppType": { - "value": "${{MICROSOFT_APP_TYPE}}" - }, - "microsoftAppTenantId": { - "value": "${{MICROSOFT_APP_TENANT_ID}}" + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceBaseName": { + "value": "bot${{RESOURCE_SUFFIX}}" + }, + "webAppSKU": { + "value": "B1" + }, + "botDisplayName": { + "value": "Bot configuration" + } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/azurebot.bicep b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/azurebot.bicep new file mode 100644 index 0000000000..a5a27b8fe4 --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/azurebot.bicep @@ -0,0 +1,42 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param identityResourceId string +param identityClientId string +param identityTenantId string +param botAppDomain string + +// Register your web service as a bot with the Bot Framework +resource botService 'Microsoft.BotService/botServices@2021-03-01' = { + kind: 'azurebot' + location: 'global' + name: botServiceName + properties: { + displayName: botDisplayName + endpoint: 'https://${botAppDomain}/api/messages' + msaAppId: identityClientId + msaAppMSIResourceId: identityResourceId + msaAppTenantId:identityTenantId + msaAppType:'UserAssignedMSI' + } + sku: { + name: botServiceSku + } +} + +// Connect the bot service to Microsoft Teams +resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { + parent: botService + location: 'global' + name: 'MsTeamsChannel' + properties: { + channelName: 'MsTeamsChannel' + } +} diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/readme.md b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/readme.md new file mode 100644 index 0000000000..d5416243cd --- /dev/null +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/infra/botRegistration/readme.md @@ -0,0 +1 @@ +The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again. \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/launchSettings.json b/samples/bot-configuration-app-auth/csharp/M365Agent/launchSettings.json index d6491ef52c..2af8ce7a8a 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/launchSettings.json +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/launchSettings.json @@ -1,15 +1,25 @@ { - "profiles": { - // Debug project within Teams - "Microsoft Teams (browser)": { - "commandName": "Project", - "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}" - }, - // Launch project within Teams without prepare app dependencies - "Microsoft Teams (browser) (skip update app)": { - "commandName": "Project", - "environmentVariables": { "UPDATE_TEAMS_APP": "false" }, - "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}" - } - } + "profiles": { + // Launch project within Microsoft 365 Agents Playground + "Microsoft 365 Agents Playground (browser)": { + "commandName": "Project", + "environmentVariables": { + "UPDATE_TEAMS_APP": "false", + "M365_AGENTS_PLAYGROUND_TARGET_SDK": "teams-ai-v2-dotnet" + }, + "launchTestTool": true, + "launchUrl": "http://localhost:56150", + }, + // Launch project within Teams + "Microsoft Teams (browser)": { + "commandName": "Project", + "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}", + }, + // Launch project within Teams without prepare app dependencies + "Microsoft Teams (browser) (skip update app)": { + "commandName": "Project", + "environmentVariables": { "UPDATE_TEAMS_APP": "false" }, + "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}" + }, + } } \ No newline at end of file diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.local.yml b/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.local.yml index 15dd443a51..27a426785d 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.local.yml +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.local.yml @@ -1,79 +1,73 @@ -# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/yaml.schema.json +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.11/yaml.schema.json # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file # Visit https://aka.ms/teamsfx-actions for details on actions -version: v1.2 - -additionalMetadata: - sampleTag: Microsoft-Teams-Samples:bot-configuration-app-auth-csharp +version: v1.11 provision: - - uses: aadApp/create # Creates a new Azure Active Directory (AAD) app to authenticate users if the environment variable that stores clientId is empty - with: - name: bot-configuration-app-auth-aad # Note: when you run aadApp/update, the AAD app name will be updated based on the definition in manifest. If you don't want to change the name, make sure the name in AAD manifest is the same with the name defined here. - generateClientSecret: true # If the value is false, the action will not generate client secret for you - signInAudience: "AzureADMyOrg" # Multitenant - writeToEnvironmentFile: # Write the information of created resources into environment file for the specified environment variable(s). - clientId: AAD_APP_CLIENT_ID - clientSecret: SECRET_AAD_APP_CLIENT_SECRET # Environment variable that starts with `SECRET_` will be stored to the .env.{envName}.user environment file - objectId: AAD_APP_OBJECT_ID - tenantId: AAD_APP_TENANT_ID - authority: AAD_APP_OAUTH_AUTHORITY - authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST - # Creates a Teams app - uses: teamsApp/create with: # Teams app name - name: bot-configuration-app-auth-${{TEAMSFX_ENV}} + name: Bot configuration${{APP_NAME_SUFFIX}} # Write the information of created resources into environment file for # the specified environment variable(s). - writeToEnvironmentFile: + writeToEnvironmentFile: teamsAppId: TEAMS_APP_ID - - uses: script + # Create or reuse an existing Microsoft Entra application for bot. + - uses: aadApp/create + with: + # The Microsoft Entra application's display name + name: Bot configuration${{APP_NAME_SUFFIX}} + generateClientSecret: true + generateServicePrincipal: true + signInAudience: AzureADMultipleOrgs + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + clientId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + clientSecret: SECRET_BOT_PASSWORD + # The Microsoft Entra application's object id created for bot. + objectId: BOT_OBJECT_ID + + # Update Microsoft Entra app using manifest + - uses: aadApp/update with: - run: - echo "::set-teamsfx-env MICROSOFT_APP_TYPE=SingleTenant"; - echo "::set-teamsfx-env MICROSOFT_APP_TENANT_ID=${{AAD_APP_TENANT_ID}}"; + manifestPath: ./aad.manifest.json + outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json # Generate runtime appsettings to JSON file - uses: file/createOrUpdateJsonFile with: - target: ../Bot configuration/appsettings.json + target: ../Bot configuration/appsettings.Development.json content: - MicrosoftAppId: ${{AAD_APP_CLIENT_ID}} - MicrosoftAppPassword: ${{SECRET_AAD_APP_CLIENT_SECRET}} - MicrosoftAppType: ${{MICROSOFT_APP_TYPE}} - MicrosoftAppTenantId: ${{MICROSOFT_APP_TENANT_ID}} + Teams: + ClientId: ${{BOT_ID}} + ClientSecret: ${{SECRET_BOT_PASSWORD}} + TenantId: ${{TEAMS_APP_TENANT_ID}} - - uses: arm/deploy # Deploy given ARM templates parallelly. - with: - subscriptionId: ${{AZURE_SUBSCRIPTION_ID}} # The AZURE_SUBSCRIPTION_ID is a built-in environment variable. TeamsFx will ask you select one subscription if its value is empty. You're free to reference other environment varialbe here, but TeamsFx will not ask you to select subscription if it's empty in this case. - resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}} # The AZURE_RESOURCE_GROUP_NAME is a built-in environment variable. TeamsFx will ask you to select or create one resource group if its value is empty. You're free to reference other environment varialbe here, but TeamsFx will not ask you to select or create resource grouop if it's empty in this case. - templates: - - path: ./infra/azure.bicep - parameters: ./infra/azure.parameters.json - deploymentName: Create-resources-for-bot - bicepCliVersion: v0.9.1 # Microsoft 365 Agents Toolkit will download this bicep CLI version from github for you, will use bicep CLI in PATH if you remove this config. - - - uses: aadApp/update # Apply the AAD manifest to an existing AAD app. Will use the object id in manifest file to determine which AAD app to update. + # Create or update the bot registration on dev.botframework.com + - uses: botFramework/create with: - manifestPath: ./aad.manifest.json # Relative path to teamsfx folder. Environment variables in manifest will be replaced before apply to AAD app - outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json + botId: ${{BOT_ID}} + name: Bot configuration + messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages + description: "" + channels: + - name: msteams # Validate using manifest schema - uses: teamsApp/validateManifest with: # Path to manifest template manifestPath: ./appPackage/manifest.json - # Build Teams app package with latest env value - uses: teamsApp/zipAppPackage with: # Path to manifest template manifestPath: ./appPackage/manifest.json outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip - outputJsonPath: ./appPackage/build/manifest.${{TEAMSFX_ENV}}.json + outputFolder: ./appPackage/build # Validate app package using validation rules - uses: teamsApp/validateAppPackage with: @@ -86,4 +80,4 @@ provision: - uses: teamsApp/update with: # Relative path to this file. This is the path for built zip file. - appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip \ No newline at end of file + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip diff --git a/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.yml b/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.yml index 7f4137b978..2ffd6bb5a8 100644 --- a/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.yml +++ b/samples/bot-configuration-app-auth/csharp/M365Agent/m365agents.yml @@ -1,10 +1,88 @@ -# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/yaml.schema.json +# yaml-language-server: $schema=https://aka.ms/m365-agents-toolkits/v1.9/yaml.schema.json # Visit https://aka.ms/teamsfx-v5.0-guide for details on this file # Visit https://aka.ms/teamsfx-actions for details on actions -version: v1.2 - -additionalMetadata: - sampleTag: Microsoft-Teams-Samples:bot-configuration-app-auth-csharp +version: v1.9 environmentFolderPath: ./env -projectId: \ No newline at end of file + +# Triggered when 'teamsapp provision' is executed +provision: + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: Bot configuration${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: arm/deploy # Deploy given ARM templates parallelly. + with: + # AZURE_SUBSCRIPTION_ID is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select a subscription. + # Referencing other environment variables with empty values + # will skip the subscription selection prompt. + subscriptionId: ${{AZURE_SUBSCRIPTION_ID}} + # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select or create one + # resource group. + # Referencing other environment variables with empty values + # will skip the resource group selection prompt. + resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}} + templates: + - path: ./infra/azure.bicep # Relative path to this file + # Relative path to this yaml file. + # Placeholders will be replaced with corresponding environment + # variable before ARM deployment. + parameters: ./infra/azure.parameters.json + # Required when deploying ARM template + deploymentName: Create-resources-for-bot + # Microsoft 365 Agents Toolkit will download this bicep CLI version from github for you, + # will use bicep CLI in PATH if you remove this config. + bicepCliVersion: v0.9.1 + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # Build Teams app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Developer Portal. + # Will use the app id in manifest file to determine which Teams app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + +# Triggered when 'teamsapp deploy' is executed +deploy: + - uses: cli/runDotnetCommand + with: + args: publish --configuration Release --runtime win-x86 --self-contained Bot + configuration.csproj + workingDirectory: ../Bot configuration + # Deploy your application to Azure App Service using the zip deploy feature. + # For additional details, refer to https://aka.ms/zip-deploy-to-app-services. + - uses: azureAppService/zipDeploy + with: + # Deploy base folder + artifactFolder: bin/Release/net10.0/win-x86/publish + # The resource id of the cloud resource to be deployed to. + # This key will be generated by arm/deploy action automatically. + # You can replace it with your existing Azure Resource id + # or add it to your environment variable file. + resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}} + workingDirectory: ../Bot configuration diff --git a/samples/bot-configuration-app-auth/csharp/README.md b/samples/bot-configuration-app-auth/csharp/README.md index 74590807b6..5883638047 100644 --- a/samples/bot-configuration-app-auth/csharp/README.md +++ b/samples/bot-configuration-app-auth/csharp/README.md @@ -77,19 +77,20 @@ The simplest way to run this sample in Teams is to use Microsoft 365 Agents Tool - Ensure that you've [enabled the Teams Channel](https://docs.microsoft.com/azure/bot-service/channel-connect-teams?view=azure-bot-service-4.0) - While registering the bot, use `https:///api/messages` as the messaging endpoint. -3. Setup NGROK - - Run ngrok - point to port 3978 +3. Setup dev tunnel - point to port 3978 - ```bash - ngrok http 3978 --host-header="localhost:3978" - ``` - - Alternatively, you can also use the `dev tunnels`. Please follow [Create and host a dev tunnel](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) and host the tunnel with anonymous user access command as shown below: + Please follow [Create and host a dev tunnel](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) and host the tunnel with anonymous user access command as shown below: ```bash devtunnel host -p 3978 --allow-anonymous ``` + Alternatively, you can also use ngrok: + + ```bash + ngrok http 3978 --host-header="localhost:3978" + ``` + 4. Setup for code - Clone the repository @@ -97,9 +98,10 @@ The simplest way to run this sample in Teams is to use Microsoft 365 Agents Tool ```bash git clone https://github.com/OfficeDev/Microsoft-Teams-Samples.git ``` - - Modify the `/appsettings.json` and fill in the following details: - - `{{MicrosoftAppId}}` - Generated from Step 1 while doing AAd app registration in Azure portal. - - `{{ClientSecret}}` - Generated from Step 1, also referred to as Client secret + - Modify the `/appsettings.Development.json` and fill in the following details: + - `ClientId` - Generated from Step 1 while doing AAd app registration in Azure portal. + - `ClientSecret` - Generated from Step 1, also referred to as Client secret + - `TenantId` - Generated from Step 1 while doing AAd app registration in Azure portal. - Run the bot from a terminal or from Visual Studio: @@ -110,7 +112,7 @@ The simplest way to run this sample in Teams is to use Microsoft 365 Agents Tool - Select `Bot Configuration.csproj` file 6. This step is related to Microsoft Teams app manifest - - **Edit** the `manifest.json` contained in the `appPackage` or `AppManifest_Hub` folder to replace your Microsoft App Id (that was created when you registered your bot earlier) *everywhere* you see the place holder string `{{Microsoft-App-Id}}` + - **Edit** the `manifest.json` contained in the `appPackage` or `AppManifest_Hub` folder to replace your Microsoft App Id (that was created when you registered your bot earlier) *everywhere* you see the place holder string ` {{BOT_ID}}` - replace `{{domain-name}}` with base Url of your domain. E.g. if you are using ngrok it would be `https://1234.ngrok-free.app` then your domain-name will be `1234.ngrok-free.app` and if you are using dev tunnels then your domain will be like: `12345.devtunnels.ms`. - **Zip** up the contents of the `Manifest` or `Manifest_hub` folder to create a `manifest.zip` - **Upload** the `manifest.zip` to Teams (in the Apps view click "Upload a custom app") @@ -155,7 +157,7 @@ Deploy your project to Azure by following these steps: ## Further reading - [Bot configuration](https://learn.microsoft.com/microsoftteams/platform/bots/how-to/bot-configuration-experience) -- [Bot Framework Documentation](https://docs.botframework.com) +- [Teams Bot Service Documentation](https://docs.botframework.com) - [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) - [Send Notification to User in Chat](https://docs.microsoft.com/graph/api/chat-sendactivitynotification?view=graph-rest-beta) - [Send Notification to User in Team](https://docs.microsoft.com/graph/api/team-sendactivitynotification?view=graph-rest-beta&tabs=http) diff --git a/samples/bot-configuration-app-auth/csharp/assets/sample.json b/samples/bot-configuration-app-auth/csharp/assets/sample.json index 44ca98179f..bdf2934343 100644 --- a/samples/bot-configuration-app-auth/csharp/assets/sample.json +++ b/samples/bot-configuration-app-auth/csharp/assets/sample.json @@ -9,7 +9,7 @@ "This sample demonstrates a configurable Teams bot that supports both static and dynamic type-ahead search controls on Adaptive Cards. It offers flexible bot configuration and reconfiguration for team and group chats." ], "creationDateTime": "2024-04-03", - "updateDateTime": "2024-10-10", + "updateDateTime": "2024-12-11", "products": [ "Teams" ],