diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation.sln b/samples/app-checkin-location/csharp/AppCheckinLocation.sln index 0e3fe9337f..2397528b8d 100644 --- a/samples/app-checkin-location/csharp/AppCheckinLocation.sln +++ b/samples/app-checkin-location/csharp/AppCheckinLocation.sln @@ -1,10 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31410.357 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppCheckinLocation", "AppCheckinLocation\AppCheckinLocation.csproj", "{BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}" EndProject +Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "TeamsApp", "TeamsApp\TeamsApp.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5D189F39-4203-4965-B996-947F7A8EA57E}" + ProjectSection(SolutionItems) = preProject + AppCheckinLocation.slnLaunch.user = AppCheckinLocation.slnLaunch.user + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +22,10 @@ Global {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.Build.0 = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user b/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user new file mode 100644 index 0000000000..0671e50375 --- /dev/null +++ b/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user @@ -0,0 +1,17 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "AppCheckinLocation\\AppCheckinLocation.csproj", + "Action": "Start", + "DebugTarget": "Start Project" + }, + { + "Path": "TeamsApp\\TeamsApp.ttkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (Browser)" + } + ] + } +] \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore b/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore new file mode 100644 index 0000000000..7466c01f9c --- /dev/null +++ b/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore @@ -0,0 +1,25 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/Properties/launchSettings.json b/samples/app-checkin-location/csharp/AppCheckinLocation/Properties/launchSettings.json index 7a1340493e..88d2fadc5a 100644 --- a/samples/app-checkin-location/csharp/AppCheckinLocation/Properties/launchSettings.json +++ b/samples/app-checkin-location/csharp/AppCheckinLocation/Properties/launchSettings.json @@ -1,28 +1,13 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:3978", - "sslPort": 0 - } - }, - "$schema": "http://json.schemastore.org/launchsettings.json", +{ "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "EchoBot": { + "Start Project": { "commandName": "Project", - "launchBrowser": true, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:3978" + "hotReloadProfile": "aspnetcore" } } } \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/README.md b/samples/app-checkin-location/csharp/README.md index c86653b868..7c4a0731d2 100644 --- a/samples/app-checkin-location/csharp/README.md +++ b/samples/app-checkin-location/csharp/README.md @@ -46,6 +46,21 @@ Please find below demo manifest which is deployed on Microsoft Azure and you can - [Teams](https://teams.microsoft.com) Microsoft Teams is installed and you have an account +- [Teams Toolkit for Visual Studio](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) + +## Run the app (Using Teams Toolkit for Visual Studio) + +The simplest way to run this sample in Teams is to use Teams Toolkit for Visual Studio. +1. Install Visual Studio 2022 **Version 17.10 Preview 4 or higher** [Visual Studio](https://visualstudio.microsoft.com/downloads/) +1. Install Teams Toolkit for Visual Studio [Teams Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) +1. In the debug dropdown menu of Visual Studio, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. In the debug dropdown menu of Visual Studio, select default startup project > **Microsoft Teams (browser)** +1. In Visual Studio, right-click your **TeamsApp** project and **Select Teams Toolkit > Prepare Teams App Dependencies** +1. Using the extension, sign in with your Microsoft 365 account where you have permissions to upload custom apps. +1. Select **Debug > Start Debugging** or **F5** to run the menu in Visual Studio. +1. In the browser that launches, select the **Add** button to install the app to Teams. +> If you do not have permission to upload custom apps (sideloading), Teams Toolkit will recommend creating and using a Microsoft 365 Developer Program account - a free program to get your own dev environment sandbox that includes Teams. + ## Setup 1) Setup for Bot diff --git a/samples/app-checkin-location/csharp/TeamsApp/TeamsApp.ttkproj b/samples/app-checkin-location/csharp/TeamsApp/TeamsApp.ttkproj new file mode 100644 index 0000000000..3fb60da121 --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/TeamsApp.ttkproj @@ -0,0 +1,9 @@ + + + + c7fd0e24-2254-4184-bf12-6c75d2752f28 + + + + + \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/color.png b/samples/app-checkin-location/csharp/TeamsApp/appPackage/color.png similarity index 100% rename from samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/color.png rename to samples/app-checkin-location/csharp/TeamsApp/appPackage/color.png diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/manifest.json b/samples/app-checkin-location/csharp/TeamsApp/appPackage/manifest.json similarity index 90% rename from samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/manifest.json rename to samples/app-checkin-location/csharp/TeamsApp/appPackage/manifest.json index f4f4699dc4..a0210b25f1 100644 --- a/samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/manifest.json +++ b/samples/app-checkin-location/csharp/TeamsApp/appPackage/manifest.json @@ -2,7 +2,8 @@ "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json", "manifestVersion": "1.19", "version": "1.0.0", - "id": "{{Microsoft-App-Id}}", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.appcheckinlocation", "developer": { "name": "Microsoft", "websiteUrl": "https://www.microsoft.com", @@ -24,7 +25,7 @@ "accentColor": "#60A18E", "bots": [ { - "botId": "{{Microsoft-App-Id}}", + "botId": "${{AAD_APP_CLIENT_ID}}", "scopes": [ "personal" ], @@ -56,6 +57,6 @@ "geolocation" ], "validDomains": [ - "{{domain-name}}" + "${{BOT_DOMAIN}}" ] } \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/outline.png b/samples/app-checkin-location/csharp/TeamsApp/appPackage/outline.png similarity index 100% rename from samples/app-checkin-location/csharp/AppCheckinLocation/AppManifest/outline.png rename to samples/app-checkin-location/csharp/TeamsApp/appPackage/outline.png diff --git a/samples/app-checkin-location/csharp/TeamsApp/env/.env.local b/samples/app-checkin-location/csharp/TeamsApp/env/.env.local new file mode 100644 index 0000000000..ae4c5f84cf --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/env/.env.local @@ -0,0 +1,25 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +TEAMSFX_M365_USER_NAME= + +BOT_ENDPOINT= +BOT_DOMAIN= + +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= \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/TeamsApp/infra/azure.bicep b/samples/app-checkin-location/csharp/TeamsApp/infra/azure.bicep new file mode 100644 index 0000000000..c3ce051b3d --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/infra/azure.bicep @@ -0,0 +1,44 @@ +@maxLength(20) +@minLength(4) +@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 + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param microsoftAppType string +param microsoftAppTenantId 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: botAadAppClientId + msaAppType: microsoftAppType + msaAppTenantId: microsoftAppType == 'SingleTenant' ? microsoftAppTenantId : '' + } + 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/app-checkin-location/csharp/TeamsApp/infra/azure.parameters.json b/samples/app-checkin-location/csharp/TeamsApp/infra/azure.parameters.json new file mode 100644 index 0000000000..6df7ae86a0 --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/infra/azure.parameters.json @@ -0,0 +1,24 @@ +{ + "$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": "app-checkin-location" + }, + "microsoftAppType": { + "value": "${{MICROSOFT_APP_TYPE}}" + }, + "microsoftAppTenantId": { + "value": "${{MICROSOFT_APP_TENANT_ID}}" + } + } +} \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/TeamsApp/launchSettings.json b/samples/app-checkin-location/csharp/TeamsApp/launchSettings.json new file mode 100644 index 0000000000..5687410386 --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/launchSettings.json @@ -0,0 +1,9 @@ +{ + "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}}" + } + } +} \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/TeamsApp/teamsapp.local.yml b/samples/app-checkin-location/csharp/TeamsApp/teamsapp.local.yml new file mode 100644 index 0000000000..f0f9a20a69 --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/teamsapp.local.yml @@ -0,0 +1,84 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:app-checkin-location-csharp + +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: app-checkin-location-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: "AzureADMultipleOrgs" # 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: app-checkin-location-${{TEAMSFX_ENV}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: script + with: + run: + # echo "::set-teamsfx-env MICROSOFT_APP_TYPE=SingleTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TYPE=MultiTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TENANT_ID=${{AAD_APP_TENANT_ID}}"; + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../AppCheckinLocation/appsettings.json + content: + MicrosoftAppId: ${{AAD_APP_CLIENT_ID}} + MicrosoftAppPassword: ${{SECRET_AAD_APP_CLIENT_SECRET}} + ApplicationBaseUrl: ${{BOT_ENDPOINT}} + + - 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 # Teams Toolkit will download this bicep CLI version from github for you, will use bicep CLI in PATH if you remove this config. + + # 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 + # 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 + # Teams 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 \ No newline at end of file diff --git a/samples/app-checkin-location/csharp/TeamsApp/teamsapp.yml b/samples/app-checkin-location/csharp/TeamsApp/teamsapp.yml new file mode 100644 index 0000000000..7d3c748b59 --- /dev/null +++ b/samples/app-checkin-location/csharp/TeamsApp/teamsapp.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:app-checkin-location-csharp + +environmentFolderPath: ./env diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation.sln b/samples/app-installation-using-qr-code/csharp/QRAppInstallation.sln index 3175007ccd..a4083df7da 100644 --- a/samples/app-installation-using-qr-code/csharp/QRAppInstallation.sln +++ b/samples/app-installation-using-qr-code/csharp/QRAppInstallation.sln @@ -1,10 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31410.357 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QRAppInstallation", "QRAppInstallation\QRAppInstallation.csproj", "{BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}" EndProject +Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "TeamsApp", "TeamsApp\TeamsApp.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A79A26F6-0AD0-48DF-BA9E-5D99F382A900}" + ProjectSection(SolutionItems) = preProject + QRAppInstallation.slnLaunch.user = QRAppInstallation.slnLaunch.user + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +22,10 @@ Global {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.Build.0 = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation.slnLaunch.user b/samples/app-installation-using-qr-code/csharp/QRAppInstallation.slnLaunch.user new file mode 100644 index 0000000000..c9789ba0f0 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/QRAppInstallation.slnLaunch.user @@ -0,0 +1,17 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "QRAppInstallation\\QRAppInstallation.csproj", + "Action": "Start", + "DebugTarget": "Start Project" + }, + { + "Path": "TeamsApp\\TeamsApp.ttkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (Browser)" + } + ] + } +] \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/.gitignore b/samples/app-installation-using-qr-code/csharp/QRAppInstallation/.gitignore new file mode 100644 index 0000000000..7466c01f9c --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/QRAppInstallation/.gitignore @@ -0,0 +1,25 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/Properties/launchSettings.json b/samples/app-installation-using-qr-code/csharp/QRAppInstallation/Properties/launchSettings.json index 7a1340493e..88d2fadc5a 100644 --- a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/Properties/launchSettings.json +++ b/samples/app-installation-using-qr-code/csharp/QRAppInstallation/Properties/launchSettings.json @@ -1,28 +1,13 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:3978", - "sslPort": 0 - } - }, - "$schema": "http://json.schemastore.org/launchsettings.json", +{ "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "EchoBot": { + "Start Project": { "commandName": "Project", - "launchBrowser": true, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "applicationUrl": "http://localhost:3978" + "hotReloadProfile": "aspnetcore" } } } \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/README.md b/samples/app-installation-using-qr-code/csharp/README.md index e88dbae916..a6f438db1a 100644 --- a/samples/app-installation-using-qr-code/csharp/README.md +++ b/samples/app-installation-using-qr-code/csharp/README.md @@ -52,6 +52,26 @@ Please find below demo manifest which is deployed on Microsoft Azure and you can - [Teams](https://teams.microsoft.com) Microsoft Teams is installed and you have an account +- [Teams Toolkit for Visual Studio](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) + +## Run the app (Using Teams Toolkit for Visual Studio) + +The simplest way to run this sample in Teams is to use Teams Toolkit for Visual Studio. +1. Install Visual Studio 2022 **Version 17.10 Preview 4 or higher** [Visual Studio](https://visualstudio.microsoft.com/downloads/) +1. Install Teams Toolkit for Visual Studio [Teams Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) +1. In the debug dropdown menu of Visual Studio, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. In the debug dropdown menu of Visual Studio, select default startup project > **Microsoft Teams (browser)** +1. In Visual Studio, right-click your **TeamsApp** project and **Select Teams Toolkit > Prepare Teams App Dependencies** +1. Using the extension, sign in with your Microsoft 365 account where you have permissions to upload custom apps. +1. Select **Debug > Start Debugging** or **F5** to run the menu in Visual Studio. +1. In the browser that launches, select the **Add** button to install the app to Teams. +> If you do not have permission to upload custom apps (sideloading), Teams Toolkit will recommend creating and using a Microsoft 365 Developer Program account - a free program to get your own dev environment sandbox that includes Teams. + +**Note:** Add the following manually under 'Azure API permissions': +- Delegated Permissions + 1. TeamsAppInstallation.ReadWriteAndConsentSelfForTeam + 2. TeamsAppInstallation.ReadWriteAndConsentForTeam + ## Setup 1) Setup for Bot SSO diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/TeamsApp.ttkproj b/samples/app-installation-using-qr-code/csharp/TeamsApp/TeamsApp.ttkproj new file mode 100644 index 0000000000..3fb60da121 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/TeamsApp.ttkproj @@ -0,0 +1,9 @@ + + + + c7fd0e24-2254-4184-bf12-6c75d2752f28 + + + + + \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/aad.manifest.json b/samples/app-installation-using-qr-code/csharp/TeamsApp/aad.manifest.json new file mode 100644 index 0000000000..d917f9ccc4 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/aad.manifest.json @@ -0,0 +1,131 @@ +{ + "id": "${{AAD_APP_OBJECT_ID}}", + "appId": "${{AAD_APP_CLIENT_ID}}", + "name": "app-installation-using-qr-code-aad", + "accessTokenAcceptedVersion": 2, + "signInAudience": "AzureADMultipleOrgs", + "oauth2AllowIdTokenImplicitFlow": true, + "oauth2AllowImplicitFlow": true, + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "idtyp", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "Microsoft Graph", + "resourceAccess": [ + { + "id": "User.Read", + "type": "Scope" + }, + { + "id": "AccessReview.ReadWrite.All", + "type": "Scope" + }, + { + "id": "Mail.Read", + "type": "Scope" + }, + { + "id": "Mail.Send", + "type": "Scope" + }, + { + "id": "openid", + "type": "Scope" + }, + { + "id": "profile", + "type": "Scope" + }, + { + "id": "User.ReadBasic.All", + "type": "Scope" + } + ] + } + ], + "oauth2Permissions": [ + { + "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.", + "adminConsentDisplayName": "Teams can access app's web APIs", + "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}", + "isEnabled": true, + "type": "User", + "userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have", + "userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf", + "value": "access_as_user" + } + ], + "preAuthorizedApplications": [ + { + "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "00000002-0000-0ff1-ce00-000000000000", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "0ec893e0-5785-4de6-99da-4ed124e5296c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4345a7b9-9a63-4910-a426-35363201d503", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + } + ], + "identifierUris":[ + "api://botid-${{AAD_APP_CLIENT_ID}}" + ], + "replyUrlsWithType":[ + { + "url": "https://${{BOT_DOMAIN}}/auth-end.html", + "type": "Web" + }, + { + "url": "https://token.botframework.com/.auth/web/redirect", + "type": "Web" + } + ] +} diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/color.png b/samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/color.png similarity index 100% rename from samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/color.png rename to samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/color.png diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/manifest.json b/samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/manifest.json similarity index 83% rename from samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/manifest.json rename to samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/manifest.json index df00c521cd..0dc24e0912 100644 --- a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/manifest.json +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/manifest.json @@ -2,7 +2,8 @@ "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json", "manifestVersion": "1.19", "version": "1.0.0", - "id": "{{Microsoft-App-Id}}", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.qrappinstallation", "developer": { "name": "Microsoft", "websiteUrl": "https://www.microsoft.com", @@ -24,7 +25,7 @@ "accentColor": "#60A18E", "bots": [ { - "botId": "{{Microsoft-App-Id}}", + "botId": "${{AAD_APP_CLIENT_ID}}", "scopes": [ "team", "personal", @@ -41,11 +42,11 @@ "media" ], "validDomains": [ - "{{domain-name}}", + "${{BOT_DOMAIN}}", "token.botframework.com" ], "webApplicationInfo": { - "id": "{{Microsoft-App-Id}}", - "resource": "api://botid-{{Microsoft-App-Id}}" + "id": "${{AAD_APP_CLIENT_ID}}", + "resource": "api://botid-${{AAD_APP_CLIENT_ID}}" } } \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/outline.png b/samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/outline.png similarity index 100% rename from samples/app-installation-using-qr-code/csharp/QRAppInstallation/AppManifest/outline.png rename to samples/app-installation-using-qr-code/csharp/TeamsApp/appPackage/outline.png diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/env/.env.local b/samples/app-installation-using-qr-code/csharp/TeamsApp/env/.env.local new file mode 100644 index 0000000000..109c844a7a --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/env/.env.local @@ -0,0 +1,27 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# 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= +CONNECTION_NAME= +TEAMSFX_M365_USER_NAME= + +BOT_ENDPOINT= +BOT_DOMAIN= + +AAD_APP_ACCESS_AS_USER_PERMISSION_ID= \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.bicep b/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.bicep new file mode 100644 index 0000000000..145ce9cd4f --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.bicep @@ -0,0 +1,76 @@ +@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 botAadAppClientId string +param botAppDomain string + +param aadAppClientId string +@secure() +param aadAppClientSecret string +param microsoftAppType string +param microsoftAppTenantId 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: botAadAppClientId + msaAppType: microsoftAppType + msaAppTenantId: microsoftAppType == 'SingleTenant' ? microsoftAppTenantId : '' + } + 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' + } +} + +resource botServiceConnection 'Microsoft.BotService/botServices/connections@2021-03-01' = { + parent: botService + name: 'oauthbotsetting' + location: 'global' + properties: { + serviceProviderDisplayName: 'Azure Active Directory v2' + serviceProviderId: '30dd229c-58e3-4a48-bdfd-91ec48eb906c' + scopes: 'User.Read' + parameters: [ + { + key: 'clientId' + value: aadAppClientId + } + { + key: 'clientSecret' + value: aadAppClientSecret + } + { + key: 'tenantID' + value: microsoftAppTenantId + } + { + key: 'tokenExchangeUrl' + value: 'api://botid-${aadAppClientId}' + } + ] + } +} + +output CONNECTION_NAME string = botServiceConnection.name diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.parameters.json b/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.parameters.json new file mode 100644 index 0000000000..ace3c881d6 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/infra/azure.parameters.json @@ -0,0 +1,30 @@ +{ + "$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": "app-installation-using-qr-code" + }, + "aadAppClientId": { + "value": "${{AAD_APP_CLIENT_ID}}" + }, + "aadAppClientSecret": { + "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" + }, + "microsoftAppType": { + "value": "${{MICROSOFT_APP_TYPE}}" + }, + "microsoftAppTenantId": { + "value": "${{MICROSOFT_APP_TENANT_ID}}" + } + } +} \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/launchSettings.json b/samples/app-installation-using-qr-code/csharp/TeamsApp/launchSettings.json new file mode 100644 index 0000000000..5687410386 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/launchSettings.json @@ -0,0 +1,9 @@ +{ + "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}}" + } + } +} \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.local.yml b/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.local.yml new file mode 100644 index 0000000000..403d480e50 --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.local.yml @@ -0,0 +1,90 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:app-installation-using-qr-code-csharp + +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: app-installation-using-qr-code-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: "AzureADMultipleOrgs" # 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: app-installation-using-qr-code-${{TEAMSFX_ENV}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: script + with: + run: + # echo "::set-teamsfx-env MICROSOFT_APP_TYPE=SingleTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TYPE=MultiTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TENANT_ID=${{AAD_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 # Teams Toolkit will download this bicep CLI version from github for you, will use bicep CLI in PATH if you remove this config. + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../QRAppInstallation/appsettings.json + content: + MicrosoftAppId: ${{AAD_APP_CLIENT_ID}} + MicrosoftAppPassword: ${{SECRET_AAD_APP_CLIENT_SECRET}} + ConnectionName: ${{CONNECTION_NAME}} + ApplicationBaseUrl: ${{BOT_ENDPOINT}} + + - 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. + 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 + + # 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 + # 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 + # Teams 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 \ No newline at end of file diff --git a/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.yml b/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.yml new file mode 100644 index 0000000000..3f6935d81d --- /dev/null +++ b/samples/app-installation-using-qr-code/csharp/TeamsApp/teamsapp.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:app-installation-using-qr-code-csharp + +environmentFolderPath: ./env \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/README.md b/samples/bot-proactive-messaging/csharp/README.md index e50e5948cb..26b73a0bd0 100644 --- a/samples/bot-proactive-messaging/csharp/README.md +++ b/samples/bot-proactive-messaging/csharp/README.md @@ -51,6 +51,20 @@ Two samples to highlight solutions to two challenges with building proactive mes - Microsoft Teams account - [.NET SDK](https://dotnet.microsoft.com/download) version 6.0 - Publicly addressable https url or tunnel such as [dev tunnel](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) or [ngrok](https://ngrok.com/) latest version or [Tunnel Relay](https://github.com/OfficeDev/microsoft-teams-tunnelrelay) +- [Teams Toolkit for Visual Studio](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) + +## Run the app (Using Teams Toolkit for Visual Studio) + +The simplest way to run this sample in Teams is to use Teams Toolkit for Visual Studio. +1. Install Visual Studio 2022 **Version 17.10 Preview 4 or higher** [Visual Studio](https://visualstudio.microsoft.com/downloads/) +1. Install Teams Toolkit for Visual Studio [Teams Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) +1. In the debug dropdown menu of Visual Studio, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. In the debug dropdown menu of Visual Studio, select default startup project > **Microsoft Teams (browser)** +1. In Visual Studio, right-click your **TeamsApp** project and **Select Teams Toolkit > Prepare Teams App Dependencies** +1. Using the extension, sign in with your Microsoft 365 account where you have permissions to upload custom apps. +1. Select **Debug > Start Debugging** or **F5** to run the menu in Visual Studio. +1. In the browser that launches, select the **Add** button to install the app to Teams. +> If you do not have permission to upload custom apps (sideloading), Teams Toolkit will recommend creating and using a Microsoft 365 Developer Program account - a free program to get your own dev environment sandbox that includes Teams. ## Setup 1. Configure public url to point to http port 5000 @@ -70,9 +84,9 @@ Two samples to highlight solutions to two challenges with building proactive mes - Ensure that you've [enabled the Teams Channel](https://docs.microsoft.com/en-us/azure/bot-service/channel-connect-teams?view=azure-bot-service-4.0) - configure the messaging endpoint in Azure bot with your application domain URL and append `/api/messages` like: `https://111xxx.ngrok-free.app/api/messages` -3. Modify the `manifest.json` in the `/AppManifest` folder and replace the `{{BOT-ID}}` with the id received while doing Microsoft Entra ID app registration in previous steps and also update the `<>` with your application domain like ngrok domain: `111xxx.ngrok-free.app` or dev tunnels domain: `12345.devtunnels.ms` excluding http/https. +3. Modify the `manifest.json` in the `/appPackage` folder and replace the `{{BOT-ID}}` with the id received while doing Microsoft Entra ID app registration in previous steps and also update the `<>` with your application domain like ngrok domain: `111xxx.ngrok-free.app` or dev tunnels domain: `12345.devtunnels.ms` excluding http/https. -4. Zip the contents of `AppManifest` into a `manifest.zip`. +4. Zip the contents of `appPackage` into a `manifest.zip`. 5. Modify the `/coordinate-logger/appsettings.local.json` file and fill in the `{{ Bot Id }}` and `{{ Bot Password }}` with the id's received while doing Microsoft Entra ID app registration in previous steps. diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/TeamsApp.ttkproj b/samples/bot-proactive-messaging/csharp/TeamsApp/TeamsApp.ttkproj new file mode 100644 index 0000000000..3fb60da121 --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/TeamsApp.ttkproj @@ -0,0 +1,9 @@ + + + + c7fd0e24-2254-4184-bf12-6c75d2752f28 + + + + + \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/AppManifest/color.png b/samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/color.png similarity index 100% rename from samples/bot-proactive-messaging/csharp/AppManifest/color.png rename to samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/color.png diff --git a/samples/bot-proactive-messaging/csharp/AppManifest/manifest.json b/samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/manifest.json similarity index 88% rename from samples/bot-proactive-messaging/csharp/AppManifest/manifest.json rename to samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/manifest.json index fb7d7dc0e8..303627508f 100644 --- a/samples/bot-proactive-messaging/csharp/AppManifest/manifest.json +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/manifest.json @@ -3,7 +3,8 @@ "manifestVersion": "1.19", "version": "1.0.0", "showLoadingIndicator": false, - "id": "{{BOT-ID}}", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.example.contoso", "developer": { "name": "Contoso", "websiteUrl": "https://www.contoso.com", @@ -26,7 +27,7 @@ "staticTabs": [], "bots": [ { - "botId": "{{BOT-ID}}", + "botId": "${{AAD_APP_CLIENT_ID}}", "scopes": [ "personal", "team" @@ -40,6 +41,6 @@ "messageTeamMembers" ], "validDomains": [ - "<>" + "${{BOT_DOMAIN}}" ] } \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/AppManifest/outline.png b/samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/outline.png similarity index 100% rename from samples/bot-proactive-messaging/csharp/AppManifest/outline.png rename to samples/bot-proactive-messaging/csharp/TeamsApp/appPackage/outline.png diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/env/.env.local b/samples/bot-proactive-messaging/csharp/TeamsApp/env/.env.local new file mode 100644 index 0000000000..76ee8a0ba6 --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/env/.env.local @@ -0,0 +1,24 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# 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= +TEAMSFX_M365_USER_NAME= + +BOT_ENDPOINT= +BOT_DOMAIN= \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/infra/azure.bicep b/samples/bot-proactive-messaging/csharp/TeamsApp/infra/azure.bicep new file mode 100644 index 0000000000..c3ce051b3d --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/infra/azure.bicep @@ -0,0 +1,44 @@ +@maxLength(20) +@minLength(4) +@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 + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param microsoftAppType string +param microsoftAppTenantId 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: botAadAppClientId + msaAppType: microsoftAppType + msaAppTenantId: microsoftAppType == 'SingleTenant' ? microsoftAppTenantId : '' + } + 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-proactive-messaging/csharp/TeamsApp/infra/azure.parameters.json b/samples/bot-proactive-messaging/csharp/TeamsApp/infra/azure.parameters.json new file mode 100644 index 0000000000..602117ff0b --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/infra/azure.parameters.json @@ -0,0 +1,24 @@ +{ + "$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-proactive-messaging" + }, + "microsoftAppType": { + "value": "${{MICROSOFT_APP_TYPE}}" + }, + "microsoftAppTenantId": { + "value": "${{MICROSOFT_APP_TENANT_ID}}" + } + } +} \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/launchSettings.json b/samples/bot-proactive-messaging/csharp/TeamsApp/launchSettings.json new file mode 100644 index 0000000000..5687410386 --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/launchSettings.json @@ -0,0 +1,9 @@ +{ + "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}}" + } + } +} \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.local.yml b/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.local.yml new file mode 100644 index 0000000000..f1c613d965 --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.local.yml @@ -0,0 +1,93 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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-proactive-messaging-csharp + +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-proactive-messaging-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: "AzureADMultipleOrgs" # 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-proactive-messaging-${{TEAMSFX_ENV}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: script + with: + run: + # echo "::set-teamsfx-env MICROSOFT_APP_TYPE=SingleTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TYPE=MultiTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TENANT_ID=${{AAD_APP_TENANT_ID}}"; + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../coordinate-logger/appsettings.json + content: + App: + Id: ${{AAD_APP_CLIENT_ID}} + Password: ${{SECRET_AAD_APP_CLIENT_SECRET}} + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../coordinate-logger/appsettings.local.json + content: + App: + Id: ${{AAD_APP_CLIENT_ID}} + Password: ${{SECRET_AAD_APP_CLIENT_SECRET}} + + - 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 # Teams Toolkit will download this bicep CLI version from github for you, will use bicep CLI in PATH if you remove this config. + + # 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 + # 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 + # Teams 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 \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.yml b/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.yml new file mode 100644 index 0000000000..ee9705c224 --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/TeamsApp/teamsapp.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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-proactive-messaging-csharp + +environmentFolderPath: ./env \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/coordinate-logger/.gitignore b/samples/bot-proactive-messaging/csharp/coordinate-logger/.gitignore new file mode 100644 index 0000000000..7466c01f9c --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/coordinate-logger/.gitignore @@ -0,0 +1,25 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/coordinate-logger/Properties/launchSettings.json b/samples/bot-proactive-messaging/csharp/coordinate-logger/Properties/launchSettings.json index 23f643a1b0..88d2fadc5a 100644 --- a/samples/bot-proactive-messaging/csharp/coordinate-logger/Properties/launchSettings.json +++ b/samples/bot-proactive-messaging/csharp/coordinate-logger/Properties/launchSettings.json @@ -1,12 +1,13 @@ { "profiles": { - "dotnet": { + "Start Project": { "commandName": "Project", - "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "hotReloadProfile": "aspnetcore" } } } \ No newline at end of file diff --git a/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.sln b/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.sln index c1473b3105..4f72a09148 100644 --- a/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.sln +++ b/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.sln @@ -1,10 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31410.357 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "msteams-app-coordinatelogger", "coordinate-logger\msteams-app-coordinatelogger.csproj", "{BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}" EndProject +Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "TeamsApp", "TeamsApp\TeamsApp.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0DDFE923-729A-4673-BD86-92B4CF4E6D66}" + ProjectSection(SolutionItems) = preProject + msteams-app-coordinatelogger.slnLaunch.user = msteams-app-coordinatelogger.slnLaunch.user + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +22,10 @@ Global {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.Build.0 = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.slnLaunch.user b/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.slnLaunch.user new file mode 100644 index 0000000000..4e8418f54c --- /dev/null +++ b/samples/bot-proactive-messaging/csharp/msteams-app-coordinatelogger.slnLaunch.user @@ -0,0 +1,17 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "coordinate-logger\\msteams-app-coordinatelogger.csproj", + "Action": "Start", + "DebugTarget": "Start Project" + }, + { + "Path": "TeamsApp\\TeamsApp.ttkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (Browser)" + } + ] + } +] \ No newline at end of file diff --git a/samples/bot-release-management/csharp/README.md b/samples/bot-release-management/csharp/README.md index 2f65996202..50265b9a79 100644 --- a/samples/bot-release-management/csharp/README.md +++ b/samples/bot-release-management/csharp/README.md @@ -36,6 +36,21 @@ This sample app integrates Azure DevOps with Teams using a bot to send notificat - [Azure DevOps](https://dev.azure.com) access to set up service hooks and add custom field in workitem. +- [Teams Toolkit for Visual Studio](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) + +## Run the app (Using Teams Toolkit for Visual Studio) + +The simplest way to run this sample in Teams is to use Teams Toolkit for Visual Studio. +1. Install Visual Studio 2022 **Version 17.10 Preview 4 or higher** [Visual Studio](https://visualstudio.microsoft.com/downloads/) +1. Install Teams Toolkit for Visual Studio [Teams Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) +1. In the debug dropdown menu of Visual Studio, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. In the debug dropdown menu of Visual Studio, select default startup project > **Microsoft Teams (browser)** +1. In Visual Studio, right-click your **TeamsApp** project and **Select Teams Toolkit > Prepare Teams App Dependencies** +1. Using the extension, sign in with your Microsoft 365 account where you have permissions to upload custom apps. +1. Select **Debug > Start Debugging** or **F5** to run the menu in Visual Studio. +1. In the browser that launches, select the **Add** button to install the app to Teams. +> If you do not have permission to upload custom apps (sideloading), Teams Toolkit will recommend creating and using a Microsoft 365 Developer Program account - a free program to get your own dev environment sandbox that includes Teams. + ## Setup **Setup NGROK** diff --git a/samples/bot-release-management/csharp/ReleaseManagement.sln b/samples/bot-release-management/csharp/ReleaseManagement.sln index a4d06c3b99..aedfea74db 100644 --- a/samples/bot-release-management/csharp/ReleaseManagement.sln +++ b/samples/bot-release-management/csharp/ReleaseManagement.sln @@ -3,7 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32414.318 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReleaseManagement", "ReleaseManagement\ReleaseManagement.csproj", "{B32E9EB2-20C3-4F6C-8623-B9B24A839D02}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReleaseManagement", "ReleaseManagement\ReleaseManagement.csproj", "{B32E9EB2-20C3-4F6C-8623-B9B24A839D02}" +EndProject +Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "TeamsApp", "TeamsApp\TeamsApp.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2D3287BC-75E7-4940-B209-9E78F3DFD755}" + ProjectSection(SolutionItems) = preProject + ReleaseManagement.slnLaunch.user = ReleaseManagement.slnLaunch.user + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +22,10 @@ Global {B32E9EB2-20C3-4F6C-8623-B9B24A839D02}.Debug|Any CPU.Build.0 = Debug|Any CPU {B32E9EB2-20C3-4F6C-8623-B9B24A839D02}.Release|Any CPU.ActiveCfg = Release|Any CPU {B32E9EB2-20C3-4F6C-8623-B9B24A839D02}.Release|Any CPU.Build.0 = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/bot-release-management/csharp/ReleaseManagement.slnLaunch.user b/samples/bot-release-management/csharp/ReleaseManagement.slnLaunch.user new file mode 100644 index 0000000000..2552b529f5 --- /dev/null +++ b/samples/bot-release-management/csharp/ReleaseManagement.slnLaunch.user @@ -0,0 +1,17 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "ReleaseManagement\\ReleaseManagement.csproj", + "Action": "Start", + "DebugTarget": "Start Project" + }, + { + "Path": "TeamsApp\\TeamsApp.ttkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (Browser)" + } + ] + } +] \ No newline at end of file diff --git a/samples/bot-release-management/csharp/ReleaseManagement/.gitignore b/samples/bot-release-management/csharp/ReleaseManagement/.gitignore new file mode 100644 index 0000000000..7466c01f9c --- /dev/null +++ b/samples/bot-release-management/csharp/ReleaseManagement/.gitignore @@ -0,0 +1,25 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json \ No newline at end of file diff --git a/samples/bot-release-management/csharp/ReleaseManagement/Properties/launchSettings.json b/samples/bot-release-management/csharp/ReleaseManagement/Properties/launchSettings.json index cd53f651e9..88d2fadc5a 100644 --- a/samples/bot-release-management/csharp/ReleaseManagement/Properties/launchSettings.json +++ b/samples/bot-release-management/csharp/ReleaseManagement/Properties/launchSettings.json @@ -1,28 +1,13 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:3978", - "sslPort": 0 - } - }, +{ "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Release Management": { + "Start Project": { "commandName": "Project", - "launchBrowser": true, - "applicationUrl": "https://localhost:3979;http://localhost:3978", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "hotReloadProfile": "aspnetcore" } } -} +} \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/TeamsApp.ttkproj b/samples/bot-release-management/csharp/TeamsApp/TeamsApp.ttkproj new file mode 100644 index 0000000000..3fb60da121 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/TeamsApp.ttkproj @@ -0,0 +1,9 @@ + + + + c7fd0e24-2254-4184-bf12-6c75d2752f28 + + + + + \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/aad.manifest.json b/samples/bot-release-management/csharp/TeamsApp/aad.manifest.json new file mode 100644 index 0000000000..ca24299316 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/aad.manifest.json @@ -0,0 +1,127 @@ +{ + "id": "${{AAD_APP_OBJECT_ID}}", + "appId": "${{AAD_APP_CLIENT_ID}}", + "name": "bot-release-management-aad", + "accessTokenAcceptedVersion": 2, + "signInAudience": "AzureADMultipleOrgs", + "oauth2AllowIdTokenImplicitFlow": true, + "oauth2AllowImplicitFlow": true, + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "idtyp", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "Microsoft Graph", + "resourceAccess": [ + { + "id": "User.Read", + "type": "Scope" + }, + { + "id": "Chat.Create", + "type": "Role" + }, + { + "id": "TeamsAppInstallation.ReadWriteForChat.All", + "type": "Role" + }, + { + "id": "AppCatalog.Read.All", + "type": "Role" + }, + { + "id": "User.Read.All", + "type": "Role" + }, + { + "id": "Teamwork.Migrate.All", + "type": "Role" + } + ] + } + ], + "oauth2Permissions": [ + { + "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.", + "adminConsentDisplayName": "Teams can access app's web APIs", + "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}", + "isEnabled": true, + "type": "User", + "userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have", + "userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf", + "value": "access_as_user" + } + ], + "preAuthorizedApplications": [ + { + "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "00000002-0000-0ff1-ce00-000000000000", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "0ec893e0-5785-4de6-99da-4ed124e5296c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4345a7b9-9a63-4910-a426-35363201d503", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + } + ], + "identifierUris":[ + "api://botid-${{AAD_APP_CLIENT_ID}}" + ], + "replyUrlsWithType":[ + { + "url": "https://${{BOT_DOMAIN}}/auth-end.html", + "type": "Web" + }, + { + "url": "https://token.botframework.com/.auth/web/redirect", + "type": "Web" + } + ] +} diff --git a/samples/bot-release-management/csharp/ReleaseManagement/AppManifest/color.png b/samples/bot-release-management/csharp/TeamsApp/appPackage/color.png similarity index 100% rename from samples/bot-release-management/csharp/ReleaseManagement/AppManifest/color.png rename to samples/bot-release-management/csharp/TeamsApp/appPackage/color.png diff --git a/samples/bot-release-management/csharp/ReleaseManagement/AppManifest/manifest.json b/samples/bot-release-management/csharp/TeamsApp/appPackage/manifest.json similarity index 86% rename from samples/bot-release-management/csharp/ReleaseManagement/AppManifest/manifest.json rename to samples/bot-release-management/csharp/TeamsApp/appPackage/manifest.json index dcd5da445b..29477470d7 100644 --- a/samples/bot-release-management/csharp/ReleaseManagement/AppManifest/manifest.json +++ b/samples/bot-release-management/csharp/TeamsApp/appPackage/manifest.json @@ -2,7 +2,8 @@ "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json", "manifestVersion": "1.19", "version": "1.0.0", - "id": "", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.releasemanagement", "developer": { "name": "Microsoft", "websiteUrl": "https://www.microsoft.com", @@ -24,7 +25,7 @@ "accentColor": "#235EA5", "bots": [ { - "botId": "", + "botId": "${{AAD_APP_CLIENT_ID}}", "scopes": [ "groupChat" ], @@ -32,7 +33,7 @@ } ], "validDomains": [ - "<>" + "${{BOT_DOMAIN}}" ], "permissions": [ "messageTeamMembers" diff --git a/samples/bot-release-management/csharp/ReleaseManagement/AppManifest/outline.png b/samples/bot-release-management/csharp/TeamsApp/appPackage/outline.png similarity index 100% rename from samples/bot-release-management/csharp/ReleaseManagement/AppManifest/outline.png rename to samples/bot-release-management/csharp/TeamsApp/appPackage/outline.png diff --git a/samples/bot-release-management/csharp/TeamsApp/env/.env.local b/samples/bot-release-management/csharp/TeamsApp/env/.env.local new file mode 100644 index 0000000000..ed425de596 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/env/.env.local @@ -0,0 +1,27 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +TEAMSFX_M365_USER_NAME= + +BOT_ENDPOINT= +BOT_DOMAIN= + +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= +CONNECTION_NAME= +AAD_APP_ACCESS_AS_USER_PERMISSION_ID= \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/infra/azure.bicep b/samples/bot-release-management/csharp/TeamsApp/infra/azure.bicep new file mode 100644 index 0000000000..145ce9cd4f --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/infra/azure.bicep @@ -0,0 +1,76 @@ +@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 botAadAppClientId string +param botAppDomain string + +param aadAppClientId string +@secure() +param aadAppClientSecret string +param microsoftAppType string +param microsoftAppTenantId 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: botAadAppClientId + msaAppType: microsoftAppType + msaAppTenantId: microsoftAppType == 'SingleTenant' ? microsoftAppTenantId : '' + } + 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' + } +} + +resource botServiceConnection 'Microsoft.BotService/botServices/connections@2021-03-01' = { + parent: botService + name: 'oauthbotsetting' + location: 'global' + properties: { + serviceProviderDisplayName: 'Azure Active Directory v2' + serviceProviderId: '30dd229c-58e3-4a48-bdfd-91ec48eb906c' + scopes: 'User.Read' + parameters: [ + { + key: 'clientId' + value: aadAppClientId + } + { + key: 'clientSecret' + value: aadAppClientSecret + } + { + key: 'tenantID' + value: microsoftAppTenantId + } + { + key: 'tokenExchangeUrl' + value: 'api://botid-${aadAppClientId}' + } + ] + } +} + +output CONNECTION_NAME string = botServiceConnection.name diff --git a/samples/bot-release-management/csharp/TeamsApp/infra/azure.parameters.json b/samples/bot-release-management/csharp/TeamsApp/infra/azure.parameters.json new file mode 100644 index 0000000000..24790246f7 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/infra/azure.parameters.json @@ -0,0 +1,30 @@ +{ + "$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-release-management" + }, + "aadAppClientId": { + "value": "${{AAD_APP_CLIENT_ID}}" + }, + "aadAppClientSecret": { + "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" + }, + "microsoftAppType": { + "value": "${{MICROSOFT_APP_TYPE}}" + }, + "microsoftAppTenantId": { + "value": "${{MICROSOFT_APP_TENANT_ID}}" + } + } +} \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/launchSettings.json b/samples/bot-release-management/csharp/TeamsApp/launchSettings.json new file mode 100644 index 0000000000..5687410386 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/launchSettings.json @@ -0,0 +1,9 @@ +{ + "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}}" + } + } +} \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/teamsapp.local.yml b/samples/bot-release-management/csharp/TeamsApp/teamsapp.local.yml new file mode 100644 index 0000000000..ac6c7c0b9d --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/teamsapp.local.yml @@ -0,0 +1,89 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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-release-management-csharp + +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-release-management-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: "AzureADMultipleOrgs" # 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-release-management-${{TEAMSFX_ENV}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: script + with: + run: + # echo "::set-teamsfx-env MICROSOFT_APP_TYPE=SingleTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TYPE=MultiTenant"; + echo "::set-teamsfx-env MICROSOFT_APP_TENANT_ID=${{AAD_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 # Teams Toolkit will download this bicep CLI version from github for you, will use bicep CLI in PATH if you remove this config. + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../ReleaseManagement/appsettings.json + content: + MicrosoftAppId: ${{AAD_APP_CLIENT_ID}} + MicrosoftAppPassword: ${{SECRET_AAD_APP_CLIENT_SECRET}} + MicrosoftAppTenantId: ${{MICROSOFT_APP_TENANT_ID}} + + - 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. + 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 + + # 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 + # 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 + # Teams 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 \ No newline at end of file diff --git a/samples/bot-release-management/csharp/TeamsApp/teamsapp.yml b/samples/bot-release-management/csharp/TeamsApp/teamsapp.yml new file mode 100644 index 0000000000..a16309b4e1 --- /dev/null +++ b/samples/bot-release-management/csharp/TeamsApp/teamsapp.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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-release-management-csharp + +environmentFolderPath: ./env diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting.sln b/samples/graph-bulk-meetings/csharp/EventMeeting.sln index 6dc72d2534..ee3bab3eea 100644 --- a/samples/graph-bulk-meetings/csharp/EventMeeting.sln +++ b/samples/graph-bulk-meetings/csharp/EventMeeting.sln @@ -5,6 +5,13 @@ VisualStudioVersion = 17.2.32602.215 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventMeeting", "EventMeeting\EventMeeting.csproj", "{72F9A2D9-07B2-460C-892F-1C57D0D19893}" EndProject +Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "TeamsApp", "TeamsApp\TeamsApp.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{41F9B0B7-81ED-405E-94F4-FA8B0B2565CE}" + ProjectSection(SolutionItems) = preProject + EventMeeting.slnLaunch.user = EventMeeting.slnLaunch.user + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +22,10 @@ Global {72F9A2D9-07B2-460C-892F-1C57D0D19893}.Debug|Any CPU.Build.0 = Debug|Any CPU {72F9A2D9-07B2-460C-892F-1C57D0D19893}.Release|Any CPU.ActiveCfg = Release|Any CPU {72F9A2D9-07B2-460C-892F-1C57D0D19893}.Release|Any CPU.Build.0 = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting.slnLaunch.user b/samples/graph-bulk-meetings/csharp/EventMeeting.slnLaunch.user new file mode 100644 index 0000000000..b3272cb98c --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/EventMeeting.slnLaunch.user @@ -0,0 +1,17 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "EventMeeting\\EventMeeting.csproj", + "Action": "Start", + "DebugTarget": "Start Project" + }, + { + "Path": "TeamsApp\\TeamsApp.ttkproj", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (Browser)" + } + ] + } +] \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting/.gitignore b/samples/graph-bulk-meetings/csharp/EventMeeting/.gitignore new file mode 100644 index 0000000000..4596bae4d8 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/EventMeeting/.gitignore @@ -0,0 +1,25 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting/Properties/launchSettings.json b/samples/graph-bulk-meetings/csharp/EventMeeting/Properties/launchSettings.json index f76e9588ed..a886e16c56 100644 --- a/samples/graph-bulk-meetings/csharp/EventMeeting/Properties/launchSettings.json +++ b/samples/graph-bulk-meetings/csharp/EventMeeting/Properties/launchSettings.json @@ -1,28 +1,13 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:3978", - "sslPort": 0 - } - }, +{ "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "GraphTeamTag": { + "Start Project": { "commandName": "Project", - "launchBrowser": true, + "dotnetRunMessages": true, "applicationUrl": "http://localhost:3978", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "hotReloadProfile": "aspnetcore" } } -} +} \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/README.md b/samples/graph-bulk-meetings/csharp/README.md index 64f2af456a..19e439febc 100644 --- a/samples/graph-bulk-meetings/csharp/README.md +++ b/samples/graph-bulk-meetings/csharp/README.md @@ -35,6 +35,20 @@ This sample application allows users to efficiently create multiple meetings in - [dev tunnel](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) or [ngrok](https://ngrok.com/download) latest version or equivalent tunneling solution - [M365 developer account](https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/prepare-your-o365-tenant) or access to a Teams account with the appropriate permissions to install an app. +- [Teams Toolkit for Visual Studio](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) + +## Run the app (Using Teams Toolkit for Visual Studio) + +The simplest way to run this sample in Teams is to use Teams Toolkit for Visual Studio. +1. Install Visual Studio 2022 **Version 17.10 Preview 4 or higher** [Visual Studio](https://visualstudio.microsoft.com/downloads/) +1. Install Teams Toolkit for Visual Studio [Teams Toolkit extension](https://learn.microsoft.com/en-us/microsoftteams/platform/toolkit/toolkit-v4/install-teams-toolkit-vs?pivots=visual-studio-v17-7) +1. In the debug dropdown menu of Visual Studio, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. In the debug dropdown menu of Visual Studio, select default startup project > **Microsoft Teams (browser)** +1. In Visual Studio, right-click your **TeamsApp** project and **Select Teams Toolkit > Prepare Teams App Dependencies** +1. Using the extension, sign in with your Microsoft 365 account where you have permissions to upload custom apps. +1. Select **Debug > Start Debugging** or **F5** to run the menu in Visual Studio. +1. In the browser that launches, select the **Add** button to install the app to Teams. +> If you do not have permission to upload custom apps (sideloading), Teams Toolkit will recommend creating and using a Microsoft 365 Developer Program account - a free program to get your own dev environment sandbox that includes Teams. ## Setup @@ -89,11 +103,11 @@ Modify the `appsettings.json` file with the following details: - Update configuration with the ```MicrosoftAppId```, ```MicrosoftAppPassword``` and ```MicrosoftAppTenantId``` values received while doing Microsoft Entra ID app registration in your Azure portal. - Press `F5` to run the project -1) Modify the `manifest.json` in the `/AppManifest` folder +1) Modify the `manifest.json` in the `/appPackage` folder Replace the following details: - - `<>` with your MicrosoftAppId received after doing Microsoft Entra ID app registration in your Azure portal. - - `{{BASE-URL}}` with base Url 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 `AppManifest` folder to create a `manifest.zip` + - `{{AAD_APP_CLIENT_ID}}` with your MicrosoftAppId received after doing Microsoft Entra ID app registration in your Azure portal. + - `{{BOT_DOMAIN}}` with base Url 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 `appPackage` folder to create a `manifest.zip` - **Upload** the `manifest.zip` to Teams (in the Apps view click "Upload a custom app") ## Running the sample diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/TeamsApp.ttkproj b/samples/graph-bulk-meetings/csharp/TeamsApp/TeamsApp.ttkproj new file mode 100644 index 0000000000..3fb60da121 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/TeamsApp.ttkproj @@ -0,0 +1,9 @@ + + + + c7fd0e24-2254-4184-bf12-6c75d2752f28 + + + + + \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/aad.manifest.json b/samples/graph-bulk-meetings/csharp/TeamsApp/aad.manifest.json new file mode 100644 index 0000000000..67f5f6c476 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/aad.manifest.json @@ -0,0 +1,129 @@ +{ + "id": "${{AAD_APP_OBJECT_ID}}", + "appId": "${{AAD_APP_CLIENT_ID}}", + "name": "graph-bulk-meetings-aad", + "accessTokenAcceptedVersion": 2, + "signInAudience": "AzureADMultipleOrgs", + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "idtyp", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "Microsoft Graph", + "resourceAccess": [ + { + "id": "User.Read", + "type": "Scope" + }, + { + "id": "Calendars.Read", + "type": "Role" + }, + { + "id": "Calendars.ReadWrite", + "type": "Role" + }, + { + "id": "OnlineMeetings.Read.All", + "type": "Role" + }, + { + "id": "OnlineMeetings.ReadWrite.All", + "type": "Role" + } + ] + } + ], + "oauth2Permissions": [ + { + "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.", + "adminConsentDisplayName": "Teams can access app's web APIs", + "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}", + "isEnabled": true, + "type": "User", + "userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have", + "userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf", + "value": "access_as_user" + } + ], + "preAuthorizedApplications": [ + { + "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "00000002-0000-0ff1-ce00-000000000000", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "0ec893e0-5785-4de6-99da-4ed124e5296c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4345a7b9-9a63-4910-a426-35363201d503", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + } + ], + "identifierUris": [ + "api://${{TAB_DOMAIN}}/${{AAD_APP_CLIENT_ID}}" + ], + "replyUrlsWithType": [ + { + "url": "${{TAB_ENDPOINT}}/auth-end.html", + "type": "Web" + }, + { + "url": "${{TAB_ENDPOINT}}/auth-end.html?clientId=${{AAD_APP_CLIENT_ID}}", + "type": "Spa" + }, + { + "url": "${{TAB_ENDPOINT}}/blank-auth-end.html", + "type": "Spa" + }, + { + "url": "${{TAB_ENDPOINT}}/Auth/End", + "type": "Spa" + } + ] +} \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/color.png b/samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/color.png similarity index 100% rename from samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/color.png rename to samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/color.png diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/manifest.json b/samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/manifest.json similarity index 81% rename from samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/manifest.json rename to samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/manifest.json index d682971881..1b6d8dfaf5 100644 --- a/samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/manifest.json +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/manifest.json @@ -2,7 +2,8 @@ "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json", "manifestVersion": "1.19", "version": "1.0.0", - "id": "<>", + "id": "${{TEAMS_APP_ID}}", + "packageName": "com.microsoft.teams.botmeetingevents", "developer": { "name": "Microsoft", "websiteUrl": "https://www.microsoft.com", @@ -20,7 +21,7 @@ "accentColor": "#5558AF", "configurableTabs": [ { - "configurationUrl": "https://{{BASE-URL}}/configure", + "configurationUrl": "https://${{BOT_DOMAIN}}/configure", "canUpdateConfiguration": true, "scopes": [ "team", @@ -34,7 +35,7 @@ }, "bots": [ { - "botId": "<>", + "botId": "${{AAD_APP_CLIENT_ID}}", "scopes": [ "team", "personal", @@ -45,12 +46,12 @@ ], "permissions": [ "identity", "messageTeamMembers" ], "validDomains": [ - "<>", + "${{BOT_DOMAIN}}", "token.botframework.com" ], "webApplicationInfo": { - "id": "<>", - "resource": "https://{{BASE-URL}}", + "id": "${{AAD_APP_CLIENT_ID}}", + "resource": "https://${{BOT_DOMAIN}}", "applicationPermissions": [ "OnlineMeeting.ReadBasic.Chat" ] diff --git a/samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/outline.png b/samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/outline.png similarity index 100% rename from samples/graph-bulk-meetings/csharp/EventMeeting/AppManifest/outline.png rename to samples/graph-bulk-meetings/csharp/TeamsApp/appPackage/outline.png diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/env/.env.local b/samples/graph-bulk-meetings/csharp/TeamsApp/env/.env.local new file mode 100644 index 0000000000..6d0bd46173 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/env/.env.local @@ -0,0 +1,23 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local + +# Generated during provision, you can also add your own variables. +TEAMS_APP_ID= +AAD_APP_CLIENT_ID= +AAD_APP_OBJECT_ID= +AAD_APP_OAUTH2_PERMISSION_ID= +AAD_APP_TENANT_ID= +AAD_APP_OAUTH_AUTHORITY_HOST= +AAD_APP_OAUTH_AUTHORITY= +TAB_ENDPOINT= + +APP_NAME_SUFFIX= +TAB_DOMAIN= +TEAMS_APP_TENANT_ID= +AAD_APP_ACCESS_AS_USER_PERMISSION_ID= +TEAMSFX_M365_USER_NAME= + +BOT_ENDPOINT= +BOT_DOMAIN= \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/launchSettings.json b/samples/graph-bulk-meetings/csharp/TeamsApp/launchSettings.json new file mode 100644 index 0000000000..5687410386 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/launchSettings.json @@ -0,0 +1,9 @@ +{ + "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}}" + } + } +} \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.local.yml b/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.local.yml new file mode 100644 index 0000000000..1337410d07 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.local.yml @@ -0,0 +1,100 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:graph-bulk-meetings-csharp + +provision: + # Creates a new Azure Active Directory (AAD) app to authenticate users if + # the environment variable that stores clientId is empty + - uses: aadApp/create + with: + # 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. + name: graph-bulk-meetings-aad + # If the value is false, the action will not generate client secret for you + generateClientSecret: true + # Authenticate users with a Microsoft work or school account in your + # organization's Azure AD tenant (for example, single tenant). + signInAudience: AzureADMultipleOrgs + # Write the information of created resources into environment file for the + # specified environment variable(s). + writeToEnvironmentFile: + clientId: AAD_APP_CLIENT_ID + # Environment variable that starts with `SECRET_` will be stored to the + # .env.{envName}.user environment file + clientSecret: SECRET_AAD_APP_CLIENT_SECRET + objectId: AAD_APP_OBJECT_ID + tenantId: AAD_APP_TENANT_ID + authority: AAD_APP_OAUTH_AUTHORITY + authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST + + # Set TAB_DOMAIN and TAB_ENDPOINT for local launch + - uses: script + with: + run: + echo "::set-teamsfx-env TAB_DOMAIN=localhost:3978"; + echo "::set-teamsfx-env TAB_ENDPOINT=http://localhost:3978"; + + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: graph-bulk-meetings-${{TEAMSFX_ENV}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: + target: ../EventMeeting/appsettings.json + content: + MicrosoftAppId: ${{AAD_APP_CLIENT_ID}} + MicrosoftAppPassword: ${{SECRET_AAD_APP_CLIENT_SECRET}} + MicrosoftAppTenantId: ${{AAD_APP_TENANT_ID}} + + # Apply the AAD manifest to an existing AAD app. Will use the object id in + # manifest file to determine which AAD app to update. + - uses: aadApp/update + with: + # Relative path to this file. Environment variables in manifest will + # be replaced before apply to AAD app + manifestPath: ./aad.manifest.json + outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json + + # 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 + # 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 + # Teams 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 + + # Run npm command for client + - uses: cli/runNpmCommand + with: + workingDirectory: ../EventMeeting/ClientApp + args: install --no-audit \ No newline at end of file diff --git a/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.yml b/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.yml new file mode 100644 index 0000000000..56003df805 --- /dev/null +++ b/samples/graph-bulk-meetings/csharp/TeamsApp/teamsapp.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.2/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:graph-bulk-meetings-csharp + +environmentFolderPath: ./env \ No newline at end of file