├── .gitignore
├── LICENSE
├── README.md
├── template-bot-master-csharp.sln
└── template-bot-master-csharp
├── App_Start
└── WebApiConfig.cs
├── DialogMatches.cs
├── Global.asax
├── Global.asax.cs
├── Properties
├── AssemblyInfo.cs
├── Strings.Designer.cs
└── Strings.resx
├── Web.Debug.config
├── Web.Release.config
├── Web.config
├── composeExtensionSettings.html
├── default.htm
├── manifest
├── bot_blue.png
└── manifest.json
├── middleware
├── AdaptiveCardSubmitActionHandler.cs
├── Middleware.cs
└── StripBotAtMentions.cs
├── packages.config
├── popUpSignin.html
├── public
├── assets
│ ├── ActionableCardIconImage.png
│ ├── computer.jpg
│ ├── computer_people.jpg
│ ├── computer_person.jpg
│ └── mascot.png
└── tab
│ └── tabConfig
│ ├── index.html
│ ├── tab.aspx
│ ├── tab.aspx.cs
│ └── tab.aspx.designer.cs
├── src
├── controllers
│ └── MessagesController.cs
└── dialogs
│ ├── RootDialog.cs
│ └── examples
│ ├── auth
│ ├── facebook
│ │ ├── FacebookHelpers.cs
│ │ ├── OAuthCallbackController.cs
│ │ └── SimpleFacebookAuthDialog.cs
│ └── vsts
│ │ ├── OAuthCallbackVSTSController.cs
│ │ ├── VSTSAPICallDialog.cs
│ │ ├── VSTSGetworkItemDialog.cs
│ │ └── VSTSHelpers.cs
│ ├── basic
│ ├── AdaptiveCardDialog.cs
│ ├── GetLastDialogUsedDialog.cs
│ ├── HelloDialog.cs
│ ├── HeroCardDialog.cs
│ ├── MessagebackDialog.cs
│ ├── MultiDialog.cs
│ ├── O365ConnectorCardActionsDialog.cs
│ ├── O365ConnectorCardDialog.cs
│ ├── PopupSigninCardDialog.cs
│ └── ThumbnailcardDialog.cs
│ ├── moderate
│ ├── BeginDialogExampleDialog.cs
│ ├── ListNamesDialog.cs
│ ├── PromptDialog.cs
│ ├── Quiz1Dialog.cs
│ ├── Quiz2Dialog.cs
│ └── QuizFullDialog.cs
│ └── teams
│ ├── AtMentionDialog.cs
│ ├── DeepLinkStaticTabDialog.cs
│ ├── DisplayCardsDialog.cs
│ ├── FetchRosterDialog.cs
│ ├── FetchTeamsInfoDialog.cs
│ ├── HelpDialog.cs
│ ├── ProactiveMsgTo1to1Dialog.cs
│ ├── UpdateCardMsgDialog.cs
│ ├── UpdateCardMsgSetupDialog.cs
│ ├── UpdateTextMsgDialog.cs
│ └── UpdateTextMsgSetupDialog.cs
├── template-bot-master-csharp.csproj
└── utility
├── InvokeHandler.cs
├── TemplateUtility.cs
└── WikipediaComposeExtension.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | products:
4 | - office-teams
5 | - office-365
6 | languages:
7 | - csharp
8 | extensions:
9 | contentType: samples
10 | technologies:
11 | - Tabs
12 | - Microsoft Bot Framework
13 | createdDate: 9/22/2017 5:54:09 PM
14 | description: "Sample that shows how to build a bot for Microsoft Teams in C#."
15 | ---
16 |
17 | #### **NOTE:** This repository is now archived. Its contents have moved [here](https://github.com/OfficeDev/Microsoft-Teams-Samples/tree/main/samples/app-complete-sample/csharp).
18 |
19 | # Microsoft Teams Bot in C#
20 |
21 | Sample that shows how to build a bot for Microsoft Teams in C#.
22 |
23 | ## Prerequisites
24 |
25 | * Install Git for windows: https://git-for-windows.github.io/
26 |
27 | * Clone this repo:
28 | ```bash
29 | git clone https://github.com/OfficeDev/microsoft-teams-template-bot-CSharp.git
30 | ```
31 |
32 | * Install Visual Studio and launch it as an administrator
33 |
34 | * Build the solution to download all configured NuGet packages
35 |
36 | * (Only needed if wanting to run in Microsoft Teams)
37 | Install some sort of tunnelling service. These instructions assume you are using ngrok: https://ngrok.com/
38 |
39 | * (Only needed if wanting to run in the Bot Emulator)
40 | Install the Bot Emulator - click on "Bot Framework Emulator (Mac and Windows)": https://docs.botframework.com/en-us/downloads/#navtitle
41 | * NOTE: make sure to pin the emulator to your task bar because it can sometimes be difficult to find again
42 |
43 | ## Steps to see the bot running in the Bot Emulator
44 |
45 | NOTE: Teams does not work nor render things exactly like the Bot Emulator, but it is a quick way to see if your bot is running and functioning correctly.
46 |
47 | 1. Open the template-bot-master-csharp.sln solution with Visual Studio
48 |
49 | 2. In Visual Studio click the play button (should be defaulted to running the Microsoft Edge configuration)
50 |
51 | 3. Once the code is running, connect with the Bot Emulator to the default endpoint, "http://localhost:3979/api/messages", leaving "Microsoft App ID" and "Microsoft App Password" blank
52 |
53 | Congratulations!!! You can now chat with the bot in the Bot Emulator!
54 |
55 | ## Steps to see the full app in Microsoft Teams
56 |
57 | 1. Begin your tunnelling service to get an https endpoint.
58 |
59 | * Open a new **Command Prompt** window.
60 |
61 | * Change to the directory that contains the ngrok.exe application.
62 |
63 | * Run the command `ngrok http [port] --host-header=localhost` (you'll need the https endpoint for the bot registration) e.g.
64 | ```
65 | ngrok http 3979 --host-header=localhost
66 | ```
67 |
68 | * The ngrok application will fill the entire prompt window. Make note of the Forwarding address using https. This address is required in the next step.
69 |
70 | * Minimize the ngrok Command Prompt window. It is no longer referenced in this lab, but it must remain running.
71 |
72 |
73 |
74 | 2. Register a new bot (or update an existing one) with Bot Framework by using the https endpoint started by ngrok and the extension "/api/messages" as the full endpoint for the bot's "Messaging endpoint". e.g. "https://####abcd.ngrok.io/api/messages" - Bot registration is here (open in a new browser tab): https://dev.botframework.com/bots/new. Ignore the warning about migrating to Azure, it is not necessary for Teams-only bots. You can however safely migrate your bot to Azure if you so choose, or use the Azure portal to create your bot.
75 |
76 | > **NOTE**: When you create your bot you will create an App ID and App password - make sure you keep these for later.
77 |
78 | 3. You project needs to run with a configuration that matches your registered bot's configuration. To do this, you will need to update the web.config file:
79 |
80 | * In Visual Studio, open the Web.config file. Locate the `` section.
81 |
82 | * Enter the BotId value. The BotId is the **Bot handle** from the **Configuration** section of the bot registration.
83 |
84 | * Enter the MicrosoftAppId. The MicrosoftAppId is the app ID from the **Configuration** section of the bot registration.
85 |
86 | * Enter the MicrosoftAppPassword. The MicrosoftAppPassword is the auto-generated app password displayed in the pop-up during bot registration.
87 |
88 | * Enter the BaseUri. The BaseUri is the https endpoint generated from ngrok.
89 |
90 | Here is an example for reference:
91 |
92 |
93 |
94 |
95 |
96 |
97 | 4. In Visual Studio click the play button (should be defaulted to running the Microsoft Edge configuration)
98 |
99 | 5. Once the app is running, a manifest file is needed:
100 | * On the solution explorer of Visual Studio, navigate to the file, manifest/manifest.json - change:
101 | * <> (there are 3) change to your registered bot's app ID
102 | * <> (there are 2) change to your https endpoint from ngrok
103 | * <> (there is 1) change to your https endpoint from ngrok excluding the "https://" part
104 |
105 | * Save the file and zip this file and the bot_blue.png file (located next to it) together to create a manifest.zip file
106 |
107 | 6. Once complete, sideload your zipped manifest to a team as described here (open in a new browser tab): https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload
108 |
109 | Congratulations!!! You have just created and sideloaded your first Microsoft Teams app! Try adding a configurable tab, at-mentioning your bot by its registered name, or viewing your static tabs.
110 | NOTE: Most of this sample app's functionality will now work. The only limitations are the authentication examples because your app is not registered with AAD nor Visual Studio Team Services.
111 |
112 | ## Overview
113 |
114 | This project is meant to help a Teams developer in two ways. First, it is meant to show many examples of how an app can integrate into Teams. Second, it is meant to give a set of patterns, templates, and tools that can be used as a starting point for creating a larger, scalable, more enterprise level bot to work within Teams. Although this project focuses on creating a robust bot, it does include simples examples of tabs as well as examples of how a bot can give links into these tabs.
115 |
116 | ## What it is
117 |
118 | At a high level, this project is written in C#, built to run a .Net, and uses the BotFramework to handle the bot's requests and responses. This project is designed to be run in Visual Studio using its debugger in order to leverage breakpoints. Most directories will hold a README file which will describe what the files within that directory do.
119 | The easiest way to get started is to follow the steps listed in the "Steps to get started running the Bot Emulator". Once this is complete and running, the easiest way to add your own content is to create a new dialog in src/dialogs by copying one from src/dialogs/examples, change it accordingly, and then instantiate it with the others in the RootDialog.cs.
120 |
121 | ## General Architecture
122 |
123 | Most code files that need to be compile reside in the src directory. Most files outside of the src directory are static files used for either configuration or for providing static resources to tabs, e.g. images and html.
124 |
125 | ## Files and Directories
126 |
127 | * **manifest**
128 | This directory holds the skeleton of a manifest.json file that can be altered in order sideload this application into a team.
129 |
130 | * **middleware**
131 | This directory holds the stripping at mention for channel class and Invoke message processing.
132 |
133 | * **public**
134 | This directory holds static html, image, and javascript files used by the tabs and bot. This is not the only public directory that is used for the tabs, though. This directory holds the html and javascript used for the configuration page of the configurable tab. The main content of the static and configurable comes from the static files placed in /public/tab/tabConfig.
135 |
136 | * **src**
137 | This directory holds all the code files, which run the entire application.
138 |
139 | * **utility**
140 | This directory holds utility functions for the project.
141 |
142 | * **web.config**
143 | This file is a configuration file that can be used to update the config keys globally used in Application.
144 |
145 | ## Contributing
146 |
147 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
148 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
149 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
150 |
151 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
152 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
153 | provided by the bot. You will only need to do this once across all repos using our CLA.
154 |
155 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
156 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
157 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
158 |
--------------------------------------------------------------------------------
/template-bot-master-csharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "template-bot-master-csharp", "template-bot-master-csharp\template-bot-master-csharp.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Web.Http;
2 | using Newtonsoft.Json;
3 | using Newtonsoft.Json.Serialization;
4 |
5 | namespace Microsoft.Teams.TemplateBotCSharp
6 | {
7 | public static class WebApiConfig
8 | {
9 | public static void Register(HttpConfiguration config)
10 | {
11 | // Json settings
12 | config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
13 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
14 | config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
15 | JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
16 | {
17 | ContractResolver = new CamelCasePropertyNamesContractResolver(),
18 | Formatting = Newtonsoft.Json.Formatting.Indented,
19 | NullValueHandling = NullValueHandling.Ignore,
20 | };
21 |
22 | // Web API configuration and services
23 |
24 | // Web API routes
25 | config.MapHttpAttributeRoutes();
26 |
27 | config.Routes.MapHttpRoute(
28 | name: "DefaultApi",
29 | routeTemplate: "api/{controller}/{id}",
30 | defaults: new { id = RouteParameter.Optional }
31 | );
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/DialogMatches.cs:
--------------------------------------------------------------------------------
1 | namespace Microsoft.Teams.TemplateBotCSharp
2 | {
3 | ///
4 | /// This contains the matching expression
5 | /// commands to trigger the individual dialogs in RootDialog
6 | ///
7 | public static class DialogMatches
8 | {
9 | public const string FetchRosterApiMatch = "names";
10 |
11 | public const string FetchRosterPayloadMatch = "roster";
12 |
13 | public const string PromptFlowGameMatch = "prompt";
14 |
15 | public const string RunQuizQuestionsMatch = "quiz";
16 |
17 | public const string DialogFlowMatch = "dialog flow";
18 |
19 | public const string HelloDialogMatch1 = "hi";
20 | public const string HelloDialogMatch2 = "hello";
21 |
22 | public const string AtMentionMatch1 = "at mention";
23 | public const string AtMentionMatch2 = "atmention";
24 | public const string AtMentionMatch3 = "at-mention";
25 |
26 | public const string Help = "help";
27 |
28 | public const string MultiDialog1Match1 = "multi dialog 1";
29 |
30 | public const string MultiDialog2Match = "multi dialog 2";
31 |
32 | public const string FecthLastExecutedDialogMatch = "last dialog";
33 |
34 | public const string Send1to1Conversation = "send message to 1:1";
35 |
36 | public const string SetUpTextMsg = "setup text message";
37 | public const string UpdateLastSetupTextMsg = "update text message";
38 |
39 | public const string SetUpCardMsg = "setup card message";
40 |
41 | public const string DisplayCards = "display cards";
42 | public const string StopShowingCards = "no";
43 |
44 | public const string DeepLinkTabCard = "deep link";
45 |
46 | public const string AuthSample = "auth";
47 |
48 | public const string Facebooklogin= "fblogin";
49 | public const string Facebooklogout = "fblogout";
50 |
51 | public const string VSTSlogin = "vstslogin";
52 | public const string VSTSlogout = "vstslogout";
53 |
54 | public const string VSTSApi = "vstsapi";
55 |
56 | public const string MessageBack = "msgback";
57 |
58 | public const string LocalTime = "localtime";
59 |
60 | public const string HeroCard = "hero card";
61 | public const string ThumbnailCard = "thumbnail card";
62 |
63 | public const string O365ConnectorCardDefault = "connector card";
64 | public const string O365ConnectorCards = "connector card (.*)";
65 |
66 | public const string O365ConnectorCardActionableCardDefault = "connector card actions";
67 | public const string O365ConnectorCardActionableCards = "connector card actions (.*)";
68 |
69 | public const string PopUpSignIn = "signin";
70 |
71 | public const string TeamInfo = "team info";
72 |
73 | public const string UpdateCard = "update card message";
74 |
75 | public const string AdaptiveCard = "adaptive card";
76 | }
77 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Microsoft.Teams.TemplateBotCSharp.WebApiApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/Global.asax.cs:
--------------------------------------------------------------------------------
1 | using Autofac;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Builder.Dialogs.Internals;
4 | using Microsoft.Bot.Connector;
5 | using System.Web.Http;
6 |
7 | namespace Microsoft.Teams.TemplateBotCSharp
8 | {
9 | public class WebApiApplication : System.Web.HttpApplication
10 | {
11 | protected void Application_Start()
12 | {
13 | GlobalConfiguration.Configure(WebApiConfig.Register);
14 |
15 | // Use an in-memory store for bot data.
16 | // This registers a IBotDataStore singleton that will be used throughout the app.
17 | var store = new InMemoryDataStore();
18 |
19 | Conversation.UpdateContainer(builder =>
20 | {
21 | builder.Register(c => new CachingBotDataStore(store,
22 | CachingBotDataStoreConsistencyPolicy
23 | .LastWriteWins))
24 | .As>()
25 | .AsSelf()
26 | .InstancePerLifetimeScope();
27 | });
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Microsoft.Teams.TemplateBotCSharp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Microsoft.Teams.TemplateBotCSharp")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("a1a5f2f5-3a75-44df-af34-a48f224abb8e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/composeExtensionSettings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Bot Info
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | I prefer:
13 | Thumbnail Cards
14 | Hero Cards
15 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/default.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Microsoft.Teams.TemplateBotCSharp
9 | Describe your bot here and your terms of use etc.
10 | Visit Bot Framework to register your bot. When you register it, remember to set your bot's endpoint to
https://your_bots_hostname /api/messages
11 |
12 |
13 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/manifest/bot_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/manifest/bot_blue.png
--------------------------------------------------------------------------------
/template-bot-master-csharp/manifest/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.7/MicrosoftTeams.schema.json",
3 | "manifestVersion": "1.7",
4 | "version": "1.5",
5 | "id": "<>",
6 | "packageName": "com.skype.teams.samples.sampleapp",
7 | "developer": {
8 | "name": "Microsoft",
9 | "websiteUrl": "https://www.microsoft.com",
10 | "privacyUrl": "https://www.microsoft.com/privacy",
11 | "termsOfUseUrl": "https://www.microsoft.com/termsofuse"
12 | },
13 | "name": {
14 | "short": "Sample-App-csharp",
15 | "full": "Sample-App-csharp"
16 | },
17 | "description": {
18 | "short": "This is a small sample app we made for you!",
19 | "full": "This is a small sample app we made for you! This app has samples of all capabilities MS Teams supports."
20 | },
21 | "icons": {
22 | "outline": "bot_blue.png",
23 | "color": "bot_blue.png"
24 | },
25 | "accentColor": "#3F487F",
26 | "staticTabs": [
27 | {
28 | "contentUrl": "<>/public/tab/tabConfig/tab.aspx",
29 | "entityId": "statictab",
30 | "name": "Bot Info",
31 | "scopes": [
32 | "team",
33 | "personal"
34 | ]
35 | }
36 | ],
37 | "configurableTabs": [
38 | {
39 | "configurationUrl": "<>/public/tab/tabConfig/index.html",
40 | "canUpdateConfiguration": false,
41 | "scopes": [ "team", "groupchat" ]
42 | }
43 | ],
44 | "bots": [
45 | {
46 | "botId": "<>",
47 | "isNotificationOnly": false,
48 | "scopes": [ "team", "personal", "groupchat" ],
49 | "commandLists": [
50 | {
51 | "scopes": [
52 | "team"
53 | ],
54 | "commands": [
55 | {
56 | "title": "help",
57 | "description": "To show the list of command for user interactions"
58 | },
59 | {
60 | "title": "hello",
61 | "description": "Runs the simplest hello dialog"
62 | },
63 | {
64 | "title": "multi dialog 2",
65 | "description": "Displays a card with invoke buttons"
66 | },
67 | {
68 | "title": "roster",
69 | "description": "Fetches the full roster payload for the current conversation"
70 | },
71 | {
72 | "title": "names",
73 | "description": "Lists the names of the users for the current conversation"
74 | },
75 | {
76 | "title": "last dialog",
77 | "description": "Shows which dialog sent the last message"
78 | },
79 | {
80 | "title": "send message to 1:1",
81 | "description": "Send the user a 1:1 message"
82 | },
83 | {
84 | "title": "setup text message",
85 | "description": "Sets up a text message that can be updated"
86 | },
87 | {
88 | "title": "update text message",
89 | "description": "Updates a text message once it is setup to be updated"
90 | },
91 | {
92 | "title": "setup card message",
93 | "description": "Sets up a card that can be updated"
94 | }
95 | ]
96 | },
97 | {
98 | "scopes": [
99 | "personal"
100 | ],
101 | "commands": [
102 | {
103 | "title": "help",
104 | "description": "To show the list of command for user interactions"
105 | },
106 | {
107 | "title": "hello",
108 | "description": "Runs the simplest hello dialog"
109 | },
110 | {
111 | "title": "multi dialog 2",
112 | "description": "Displays a card with invoke buttons"
113 | },
114 | {
115 | "title": "roster",
116 | "description": "Fetches the full roster payload for the current conversation"
117 | },
118 | {
119 | "title": "names",
120 | "description": "Lists the names of the users for the current conversation"
121 | },
122 | {
123 | "title": "last dialog",
124 | "description": "Shows which dialog sent the last message"
125 | },
126 | {
127 | "title": "send message to 1:1",
128 | "description": "Send the user a 1:1 message"
129 | },
130 | {
131 | "title": "setup text message",
132 | "description": "Sets up a text message that can be updated"
133 | },
134 | {
135 | "title": "update text message",
136 | "description": "Updates a text message once it is setup to be updated"
137 | },
138 | {
139 | "title": "setup card message",
140 | "description": "Sets up a card that can be updated"
141 | }
142 | ]
143 | }
144 | ]
145 | }
146 | ],
147 | "composeExtensions": [
148 | {
149 | "botId": "<>",
150 | "canUpdateConfiguration": true,
151 | "commands": [
152 | {
153 | "id": "search123",
154 | "description": "Find a card",
155 | "title": "Search",
156 | "initialRun": true,
157 | "parameters": [
158 | {
159 | "title": "query123",
160 | "name": "query",
161 | "description": "Search string"
162 | }
163 | ]
164 | }
165 | ]
166 | }
167 | ],
168 | "permissions": [
169 | "identity",
170 | "messageTeamMembers"
171 | ],
172 | "validDomains": [
173 | "<>"
174 | ]
175 | }
176 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/middleware/AdaptiveCardSubmitActionHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 |
5 | namespace Microsoft.Teams.TemplateBotCSharp.Utility
6 | {
7 | public static partial class Middleware
8 | {
9 | public static string AdaptiveCardActionKey = "dialog";
10 |
11 | ///
12 | /// Set activity text to "adaptive card", if request is from an adaptive card
13 | ///
14 | ///
15 | ///
16 | public static Activity AdaptiveCardSubmitActionHandler(Activity activity)
17 | {
18 | // Check event text is blank, replyToId is not null, event value has isFromAdaptiveCard and messageText in incoming payload to check if the incoming
19 | // payload is from a Submit action button click from an AdaptiveCard (this is set in …\src\dialogs\examples\basic\AdaptiveCardDialog.cs) in the Submit action
20 | // data field. If so, then set the text field of the incoming payload so the BotFramework regex recognizers will route the message to the desired dialog.
21 | if (string.IsNullOrEmpty(activity.Text) && activity.ReplyToId != null && activity?.Value != null)
22 | {
23 | JObject jsonObject = activity.Value as JObject;
24 |
25 | if (jsonObject != null && jsonObject.Count > 0)
26 | {
27 | string isFromAdaptiveCard = Convert.ToString(jsonObject["isFromAdaptiveCard"]);
28 | string messageText = Convert.ToString(jsonObject["messageText"]);
29 |
30 | if (!string.IsNullOrEmpty(isFromAdaptiveCard) && isFromAdaptiveCard == "true" && !string.IsNullOrEmpty(messageText))
31 | {
32 | // set activity text "adaptive card"
33 | activity.Text = messageText;
34 | }
35 | }
36 | }
37 |
38 | return activity;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/middleware/Middleware.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using Newtonsoft.Json.Linq;
3 | using System;
4 | using System.Configuration;
5 |
6 | namespace Microsoft.Teams.TemplateBotCSharp.Utility
7 | {
8 | public static partial class Middleware
9 | {
10 | public static string TenantFilterSettingAny = "#ANY#";
11 |
12 | ///
13 | /// Here are below scenarios -
14 | /// #Scenario 1 - Reject the Bot If Tenant is configured in web.config and doesn't match with Incoming request tenant
15 | /// #Scenario 2 - Allow Bot for every Tenant if Tenant is not configured in web.config file and default value is #ANY#
16 | ///
17 | ///
18 | ///
19 | ///
20 | public static bool RejectMessageBasedOnTenant(IMessageActivity activity, string currentTenant)
21 | {
22 | if (!String.Equals(ConfigurationManager.AppSettings["OFFICE_365_TENANT_FILTER"], TenantFilterSettingAny))
23 | {
24 | //#Scenario 1
25 | return !string.Equals(ConfigurationManager.AppSettings["OFFICE_365_TENANT_FILTER"], currentTenant);
26 | }
27 | else
28 | {
29 | //Scenario 2
30 | return false;
31 | }
32 | }
33 |
34 | public static Activity ConvertActivityTextToLower(Activity activity)
35 | {
36 | //Convert input command in lower case for 1To1 and Channel users
37 | if (activity.Text != null)
38 | {
39 | activity.Text = activity.Text.ToLower();
40 | }
41 |
42 | return activity;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/middleware/StripBotAtMentions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using System;
3 |
4 | namespace Microsoft.Teams.TemplateBotCSharp.Utility
5 | {
6 | public static partial class Middleware
7 | {
8 | public static Activity StripAtMentionText(Activity activity)
9 | {
10 | if (activity == null)
11 | {
12 | throw new ArgumentNullException(nameof(activity));
13 | }
14 |
15 | foreach (var m in activity.GetMentions())
16 | {
17 | if (m.Mentioned.Id == activity.Recipient.Id)
18 | {
19 | //Bot is in the @mention list.
20 | //The below example will strip the bot name out of the message, so you can parse it as if it wasn't included.
21 | //Note that the Text object will contain the full bot name, if applicable.
22 | if (m.Text != null)
23 | activity.Text = activity.Text.Replace(m.Text, "").Trim();
24 | }
25 | }
26 |
27 | return activity;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/popUpSignin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | User Name :
10 |
11 |
12 |
13 | Password :
14 |
15 |
16 | Login
17 |
18 |
19 |
20 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/assets/ActionableCardIconImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/public/assets/ActionableCardIconImage.png
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/assets/computer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/public/assets/computer.jpg
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/assets/computer_people.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/public/assets/computer_people.jpg
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/assets/computer_person.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/public/assets/computer_person.jpg
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/assets/mascot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-sample-complete-csharp/6c0a4e6992490d0ff71368980a14bb74e6d79dc6/template-bot-master-csharp/public/assets/mascot.png
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/tab/tabConfig/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
26 |
27 |
28 | Press save to create your tab
29 |
30 |
31 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/tab/tabConfig/tab.aspx:
--------------------------------------------------------------------------------
1 | <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="tab.aspx.cs" Inherits="Microsoft.Teams.TemplateBotCSharp.src.tab.tab" %>
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/tab/tabConfig/tab.aspx.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 | using System.Web.UI.WebControls;
5 |
6 | namespace Microsoft.Teams.TemplateBotCSharp.src.tab
7 | {
8 | public partial class tab : System.Web.UI.Page
9 | {
10 | private bool IsValidFilePath { get; set; }
11 | protected void Page_Load(object sender, EventArgs e)
12 | {
13 | if (!IsPostBack)
14 | {
15 | string DirectoryName = Request.MapPath("~/src/dialogs/");
16 | if (Directory.Exists(DirectoryName))
17 | {
18 | string[] sourceCodeFiles = Directory.GetFiles(DirectoryName, "*.*", SearchOption.AllDirectories);
19 | ListOfCodeFiles.DataSource = sourceCodeFiles;
20 | ListOfCodeFiles.DataBind();
21 | }
22 | }
23 | }
24 | protected void ListOfCodeFiles_OnItemDataBound(object sender, RepeaterItemEventArgs e)
25 | {
26 | if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
27 | {
28 | LinkButton fileNameLink = (LinkButton)e.Item.FindControl("nameOfFile");
29 | String fullName = (String)e.Item.DataItem;
30 | fileNameLink.Text = fullName.Substring(fullName.LastIndexOf("\\") + 1);
31 | fileNameLink.CommandArgument = fullName.Substring(fullName.LastIndexOf("\\") + 1);
32 | }
33 | }
34 | protected void ListOfCodeFiles_OnItemCommand(object sender, RepeaterCommandEventArgs e)
35 | {
36 | StringBuilder fileCodeLines= new StringBuilder();
37 |
38 | if (e.CommandName == "GOTO")
39 | {
40 | string[] dirs = Directory.GetDirectories(Request.MapPath("~/src/dialogs/"), "*", SearchOption.AllDirectories);
41 |
42 | if (dirs.Length > 0)
43 | {
44 | foreach (string dirName in dirs)
45 | {
46 | string dirPath = dirName.Substring(dirName.IndexOf("src"), (dirName.Length - dirName.IndexOf("src")));
47 | dirPath = "~/" + dirPath.Replace("\\", "/") + "/";
48 |
49 | fileCodeLines = ReadFileContentFromPath(Request.MapPath(dirPath) + (String)e.CommandArgument);
50 |
51 | //No need to read the files once we got the content
52 | if(fileCodeLines.Length!=0)
53 | {
54 | break;
55 | }
56 | }
57 |
58 | if (!IsValidFilePath)
59 | {
60 | fileCodeLines = ReadFileContentFromPath(Request.MapPath("~/src/dialogs/") + (String)e.CommandArgument);
61 | }
62 |
63 | fileName.Text = (String)e.CommandArgument;
64 |
65 | divFileContent.Style.Add("display", "block");
66 | fileContent.Text = fileCodeLines.ToString();
67 | }
68 | }
69 | }
70 |
71 | ///
72 | /// Read the source file content
73 | ///
74 | ///
75 | ///
76 | private StringBuilder ReadFileContentFromPath(string filePath)
77 | {
78 | StringBuilder fileContent = new StringBuilder();
79 | try
80 | {
81 | string[] codeLines = File.ReadAllLines(filePath);
82 | IsValidFilePath = true;
83 |
84 | foreach (string line in codeLines)
85 | {
86 | fileContent.Append(" ");
87 | fileContent.Append("\t" + line);
88 | }
89 | }
90 | catch
91 | {
92 | // Ignore the File here
93 | }
94 |
95 | return fileContent;
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/public/tab/tabConfig/tab.aspx.designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | //
5 | // Changes to this file may cause incorrect behavior and will be lost if
6 | // the code is regenerated.
7 | //
8 | //------------------------------------------------------------------------------
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp.src.tab {
11 |
12 |
13 | public partial class tab {
14 |
15 | ///
16 | /// form1 control.
17 | ///
18 | ///
19 | /// Auto-generated field.
20 | /// To modify move field declaration from designer file to code-behind file.
21 | ///
22 | protected global::System.Web.UI.HtmlControls.HtmlForm form1;
23 |
24 | ///
25 | /// ListOfCodeFiles control.
26 | ///
27 | ///
28 | /// Auto-generated field.
29 | /// To modify move field declaration from designer file to code-behind file.
30 | ///
31 | protected global::System.Web.UI.WebControls.Repeater ListOfCodeFiles;
32 |
33 | ///
34 | /// fileName control.
35 | ///
36 | ///
37 | /// Auto-generated field.
38 | /// To modify move field declaration from designer file to code-behind file.
39 | ///
40 | protected global::System.Web.UI.WebControls.Label fileName;
41 |
42 | ///
43 | /// divFileContent control.
44 | ///
45 | ///
46 | /// Auto-generated field.
47 | /// To modify move field declaration from designer file to code-behind file.
48 | ///
49 | protected global::System.Web.UI.HtmlControls.HtmlGenericControl divFileContent;
50 |
51 | ///
52 | /// fileContent control.
53 | ///
54 | ///
55 | /// Auto-generated field.
56 | /// To modify move field declaration from designer file to code-behind file.
57 | ///
58 | protected global::System.Web.UI.WebControls.Label fileContent;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/controllers/MessagesController.cs:
--------------------------------------------------------------------------------
1 | using Autofac;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Builder.Dialogs.Internals;
4 | using Microsoft.Bot.Connector;
5 | using Microsoft.Bot.Connector.Teams;
6 | using Microsoft.Bot.Connector.Teams.Models;
7 | using Microsoft.Teams.TemplateBotCSharp.Dialogs;
8 | using Microsoft.Teams.TemplateBotCSharp.Properties;
9 | using Microsoft.Teams.TemplateBotCSharp.Utility;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 | using System.Net;
14 | using System.Net.Http;
15 | using System.Threading;
16 | using System.Threading.Tasks;
17 | using System.Web.Http;
18 |
19 | namespace Microsoft.Teams.TemplateBotCSharp
20 | {
21 | [BotAuthentication]
22 | public class MessagesController : ApiController
23 | {
24 | ///
25 | /// POST: api/Messages
26 | /// Receive a message from a user and reply to it
27 | ///
28 | public async Task Post([FromBody]Activity activity, CancellationToken cancellationToken)
29 | {
30 | var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
31 |
32 | if (activity.Type == ActivityTypes.Message)
33 | {
34 | // Special handling for a command to simulate a reset of the bot chat
35 | if (!(activity.Conversation.IsGroup ?? false) && (activity.Text == "/resetbotchat"))
36 | {
37 | return await HandleResetBotChatAsync(activity, cancellationToken);
38 | }
39 |
40 | //Set the Locale for Bot
41 | activity.Locale = TemplateUtility.GetLocale(activity);
42 |
43 | //Strip At mention from incoming request text
44 | activity = Middleware.StripAtMentionText(activity);
45 |
46 | //Convert incoming activity text to lower case, to match the intent irrespective of incoming text case
47 | activity = Middleware.ConvertActivityTextToLower(activity);
48 |
49 | //Set the OFFICE_365_TENANT_FILTER key in web.config file with Tenant Information
50 | //Validate bot for specific teams tenant if any
51 | if (Middleware.RejectMessageBasedOnTenant(activity, activity.GetTenantId()))
52 | {
53 | Activity replyActivity = activity.CreateReply();
54 | replyActivity.Text = Strings.TenantLevelDeniedAccess;
55 |
56 | await connectorClient.Conversations.ReplyToActivityAsync(replyActivity);
57 | return Request.CreateResponse(HttpStatusCode.OK);
58 | }
59 |
60 | // Set activity text if request is from an adaptive card submit action
61 | activity = Middleware.AdaptiveCardSubmitActionHandler(activity);
62 |
63 | await Conversation.SendAsync(activity, () => new RootDialog());
64 | }
65 | else if (activity.Type == ActivityTypes.MessageReaction)
66 | {
67 | var reactionsAdded = activity.ReactionsAdded;
68 | var reactionsRemoved = activity.ReactionsRemoved;
69 | var replytoId = activity.ReplyToId;
70 | Activity reply;
71 |
72 | if (reactionsAdded != null && reactionsAdded.Count > 0)
73 | {
74 | reply = activity.CreateReply(Strings.LikeMessage);
75 | await connectorClient.Conversations.ReplyToActivityAsync(reply);
76 | }
77 | else if (reactionsRemoved != null && reactionsRemoved.Count > 0)
78 | {
79 | reply = activity.CreateReply(Strings.RemoveLike);
80 | await connectorClient.Conversations.ReplyToActivityAsync(reply);
81 | }
82 |
83 | return Request.CreateResponse(HttpStatusCode.OK);
84 | }
85 | else if (activity.Type == ActivityTypes.Invoke) // Received an invoke
86 | {
87 | // Handle ComposeExtension query
88 | if (activity.IsComposeExtensionQuery())
89 | {
90 | WikipediaComposeExtension wikipediaComposeExtension = new WikipediaComposeExtension();
91 | HttpResponseMessage httpResponse = null;
92 |
93 | using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
94 | {
95 | var botDataStore = scope.Resolve>();
96 | // Handle compose extension selected item
97 | if (activity.Name == "composeExtension/selectItem")
98 | {
99 | // This handler is used to process the event when a user in Teams selects wiki item from wiki result
100 | ComposeExtensionResponse selectedItemResponse = await wikipediaComposeExtension.HandleComposeExtensionSelectedItem(activity, botDataStore);
101 | httpResponse = Request.CreateResponse(HttpStatusCode.OK, selectedItemResponse);
102 | }
103 | else
104 | {
105 | // Handle the wiki compose extension request and returned the wiki result response
106 | ComposeExtensionResponse composeExtensionResponse = await wikipediaComposeExtension.GetComposeExtensionResponse(activity, botDataStore);
107 | httpResponse = Request.CreateResponse(HttpStatusCode.OK, composeExtensionResponse);
108 | }
109 |
110 | var address = Address.FromActivity(activity);
111 | await botDataStore.FlushAsync(address, CancellationToken.None);
112 | }
113 | return httpResponse;
114 | }
115 | //Actionable Message
116 | else if (activity.IsO365ConnectorCardActionQuery())
117 | {
118 | // this will handle the request coming any action on Actionable messages
119 | return await HandleO365ConnectorCardActionQuery(activity);
120 | }
121 | //PopUp SignIn
122 | else if (activity.Name == "signin/verifyState")
123 | {
124 | // this will handle the request coming from PopUp SignIn
125 | return await PopUpSignInHandler(activity);
126 | }
127 | // Handle rest of the invoke request
128 | else
129 | {
130 | var messageActivity = (IMessageActivity)null;
131 |
132 | //this will parse the invoke value and change the message activity as well
133 | messageActivity = InvokeHandler.HandleInvokeRequest(activity);
134 |
135 | await Conversation.SendAsync(messageActivity, () => new Dialogs.RootDialog());
136 |
137 | return Request.CreateResponse(HttpStatusCode.OK);
138 | }
139 | }
140 | else
141 | {
142 | await HandleSystemMessageAsync(activity, connectorClient, cancellationToken);
143 | }
144 |
145 | var response = Request.CreateResponse(HttpStatusCode.OK);
146 |
147 | return response;
148 | }
149 |
150 | private async Task HandleSystemMessageAsync(Activity message, ConnectorClient connectorClient, CancellationToken cancellationToken)
151 | {
152 | if (message.Type == ActivityTypes.DeleteUserData)
153 | {
154 | // Implement user deletion here
155 | // If we handle user deletion, return a real message
156 | }
157 | else if (message.Type == ActivityTypes.ConversationUpdate)
158 | {
159 | // This shows how to send a welcome message in response to a conversationUpdate event
160 |
161 | // We're only interested in member added events
162 | if (message.MembersAdded?.Count > 0)
163 | {
164 | // Determine if the bot was added to the team/conversation
165 | var botId = message.Recipient.Id;
166 | var botWasAdded = message.MembersAdded.Any(member => member.Id == botId);
167 |
168 | // Create the welcome message to send
169 | Activity welcomeMessage = message.CreateReply();
170 | welcomeMessage.Text = Strings.BotWelcomeMessage;
171 |
172 | if (!(message.Conversation.IsGroup ?? false))
173 | {
174 | // 1:1 conversation event
175 |
176 | // If the user hasn't received a first-run message yet, then send a message to the user
177 | // introducing your bot and what it can do. Do NOT send this blindly, as your bot can receive
178 | // spurious conversationUpdate events, especially if you use proactive messaging.
179 | using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
180 | {
181 | var address = Address.FromActivity(message);
182 | var botDataStore = scope.Resolve>();
183 | var botData = await botDataStore.LoadAsync(address, BotStoreType.BotUserData, cancellationToken);
184 |
185 | if (!botData.GetProperty("IsFreSent"))
186 | {
187 | await connectorClient.Conversations.ReplyToActivityWithRetriesAsync(welcomeMessage, cancellationToken);
188 |
189 | // Remember that we sent the welcome message already
190 | botData.SetProperty("IsFreSent", true);
191 | await botDataStore.SaveAsync(address, BotStoreType.BotUserData, botData, cancellationToken);
192 | }
193 | else
194 | {
195 | // First-run message has already been sent, so skip sending it again.
196 | // Do not remove the check for IsFreSent above. Your bot can receive spurious conversationUpdate
197 | // activities from chat service, so if you always respond to all of them, you will send random
198 | // welcome messages to users who have already received the welcome.
199 | }
200 | }
201 | }
202 | else
203 | {
204 | // Not 1:1 chat event (bot or user was added to a team or group chat)
205 | if (botWasAdded)
206 | {
207 | // Bot was added to the team
208 | // Send a message to the team's channel, introducing your bot and what you can do
209 | await connectorClient.Conversations.ReplyToActivityWithRetriesAsync(welcomeMessage, cancellationToken);
210 | }
211 | else
212 | {
213 | // Other users were added to the team/conversation
214 | }
215 | }
216 | }
217 | }
218 | else if (message.Type == ActivityTypes.ContactRelationUpdate)
219 | {
220 | // Handle add/remove from contact lists
221 | // Activity.From + Activity.Action represent what happened
222 | }
223 | else if (message.Type == ActivityTypes.Typing)
224 | {
225 | // Handle knowing that the user is typing
226 | }
227 | else if (message.Type == ActivityTypes.Ping)
228 | {
229 | }
230 | }
231 |
232 | ///
233 | /// Handles a request from the user to simulate a new chat.
234 | ///
235 | /// The incoming message requesting the reset
236 | /// The cancellation token
237 | ///
238 | private async Task HandleResetBotChatAsync(Activity message, CancellationToken cancellationToken)
239 | {
240 | // Forget everything we know about the user
241 | using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
242 | {
243 | var address = Address.FromActivity(message);
244 | var botDataStore = scope.Resolve>();
245 | await botDataStore.SaveAsync(address, BotStoreType.BotUserData, new BotData("*"), cancellationToken);
246 | await botDataStore.SaveAsync(address, BotStoreType.BotConversationData, new BotData("*"), cancellationToken);
247 | await botDataStore.SaveAsync(address, BotStoreType.BotPrivateConversationData, new BotData("*"), cancellationToken);
248 | }
249 |
250 | // If you need to reset the user state in other services your app uses, do it here.
251 |
252 | // Synthesize a conversation update event and simulate the bot receiving it
253 | // Note that this is a fake event, as Teams does not support deleting a 1:1 conversation and re-creating it
254 | var conversationUpdateMessage = new Activity {
255 | Type = ActivityTypes.ConversationUpdate,
256 | Id = message.Id,
257 | ServiceUrl = message.ServiceUrl,
258 | From = message.From,
259 | Recipient = message.Recipient,
260 | Conversation = message.Conversation,
261 | ChannelData = message.ChannelData,
262 | ChannelId = message.ChannelId,
263 | Timestamp = message.Timestamp,
264 | MembersAdded = new List { message.From, message.Recipient },
265 | };
266 | return await this.Post(conversationUpdateMessage, cancellationToken);
267 | }
268 |
269 | ///
270 | /// Handles O365 connector card action queries.
271 | ///
272 | /// Incoming request from Bot Framework.
273 | /// Connector client instance for posting to Bot Framework.
274 | /// Task tracking operation.
275 |
276 | private static async Task HandleO365ConnectorCardActionQuery(Activity activity)
277 | {
278 | var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
279 |
280 | // Get O365 connector card query data.
281 | O365ConnectorCardActionQuery o365CardQuery = activity.GetO365ConnectorCardActionQueryData();
282 |
283 | Activity replyActivity = activity.CreateReply();
284 | replyActivity.TextFormat = "xml";
285 |
286 | replyActivity.Text = $@"
287 | Thanks, {activity.From.Name}
288 | Your input action ID:
289 | {o365CardQuery.ActionId}
290 | Your input body:
291 | {o365CardQuery.Body} ";
292 |
293 | await connectorClient.Conversations.ReplyToActivityWithRetriesAsync(replyActivity);
294 | return new HttpResponseMessage(HttpStatusCode.OK);
295 | }
296 |
297 | ///
298 | /// Handle the PopUp SignIn requests
299 | ///
300 | ///
301 | ///
302 | private static async Task PopUpSignInHandler(Activity activity)
303 | {
304 | var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
305 | Activity replyActivity = activity.CreateReply();
306 | replyActivity.Text = $@"Authentication Successful";
307 |
308 | await connectorClient.Conversations.ReplyToActivityWithRetriesAsync(replyActivity);
309 | return new HttpResponseMessage(HttpStatusCode.OK);
310 | }
311 |
312 |
313 | }
314 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/RootDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Builder.Scorables;
3 | using Microsoft.Bot.Connector;
4 | using Microsoft.Bot.Connector.Teams.Models;
5 | using Microsoft.Teams.TemplateBotCSharp.Properties;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
11 | {
12 | ///
13 | /// This is Root Dialog, its a triggring point for every Child dialog based on the RexEx Match with user input command
14 | ///
15 |
16 | [Serializable]
17 | public class RootDialog : DispatchDialog
18 | {
19 | #region Fetch Roster Api Payload Pattern
20 |
21 | [RegexPattern(DialogMatches.FetchRosterPayloadMatch)]
22 | [ScorableGroup(1)]
23 | public void FetchRosterPayLoadDetails(IDialogContext context, IActivity activity)
24 | {
25 | context.Call(new FetchRosterDialog(), this.EndFetchRosterDialog);
26 | }
27 |
28 | #endregion
29 |
30 | #region Fetch Roster Api Pattern
31 |
32 | [RegexPattern(DialogMatches.FetchRosterApiMatch)]
33 | [ScorableGroup(1)]
34 | public void FetchRoster(IDialogContext context, IActivity activity)
35 | {
36 | context.Call(new ListNamesDialog(), this.EndFetchRosterDialog);
37 | }
38 |
39 | public async Task EndFetchRosterDialog(IDialogContext context, IAwaitable result)
40 | {
41 | await context.PostAsync(Strings.ThanksRosterTitleMsg);
42 | context.Done(null);
43 | }
44 |
45 | #endregion
46 |
47 | #region Play Quiz
48 |
49 | [RegexPattern(DialogMatches.RunQuizQuestionsMatch)]
50 | [ScorableGroup(1)]
51 | public async Task RunQuiz(IDialogContext context, IActivity activity)
52 | {
53 | await this.SendWelcomeMessageQuizAsync(context,activity);
54 | }
55 | private async Task SendWelcomeMessageQuizAsync(IDialogContext context, IActivity activity)
56 | {
57 | await context.PostAsync(Strings.QuizTitleWelcomeMsg);
58 | context.Call(new QuizFullDialog(), this.EndDialog);
59 | }
60 |
61 | #endregion
62 |
63 | #region Prompt Flow Game Dialog Api Pattern
64 |
65 | [RegexPattern(DialogMatches.PromptFlowGameMatch)]
66 | [ScorableGroup(1)]
67 | public void FlowGame(IDialogContext context, IActivity activity)
68 | {
69 | context.Call(new PromptDialogExample(), this.ResumeAfterFlowGame);
70 | }
71 |
72 | public async Task ResumeAfterFlowGame(IDialogContext context, IAwaitable result)
73 | {
74 | if (result == null)
75 | {
76 | throw new InvalidOperationException((nameof(result)) + Strings.NullException);
77 | }
78 |
79 | var resultedValue = await result;
80 |
81 | if(Convert.ToBoolean(resultedValue))
82 | {
83 | await context.PostAsync(Strings.PlayGameThanksMsg);
84 | }
85 | else
86 | {
87 | await context.PostAsync(Strings.PlayGameFailMsg);
88 | }
89 |
90 | context.Done(null);
91 | }
92 |
93 | #endregion
94 |
95 | #region Dialog Flow
96 |
97 | [RegexPattern(DialogMatches.DialogFlowMatch)]
98 | [ScorableGroup(1)]
99 | public async Task RunDialogFlow(IDialogContext context, IActivity activity)
100 | {
101 | await context.PostAsync(Strings.DialogFlowStep1);
102 | await this.SendStep1MsgAsync(context, activity);
103 | }
104 |
105 | private async Task SendStep1MsgAsync(IDialogContext context, IActivity activity)
106 | {
107 | await context.PostAsync(Strings.DialogFlowStep2);
108 | context.Call(new BeginDialogExampleDialog(), this.ResumeAfterDialogFlow);
109 | }
110 |
111 | public async Task ResumeAfterDialogFlow(IDialogContext context, IAwaitable result)
112 | {
113 | await context.PostAsync(Strings.DialogFlowStep3);
114 | context.Done(null);
115 | }
116 | #endregion
117 |
118 | #region Hello Dialog
119 |
120 | [RegexPattern(DialogMatches.HelloDialogMatch1)]
121 | [RegexPattern(DialogMatches.HelloDialogMatch2)]
122 | [ScorableGroup(1)]
123 | public void RunHelloDialog(IDialogContext context, IActivity activity)
124 | {
125 | context.Call(new HelloDialog(), this.EndDialog);
126 | }
127 |
128 | #endregion
129 |
130 | #region Run at Mention Api Pattern
131 |
132 | [RegexPattern(DialogMatches.AtMentionMatch1)]
133 | [RegexPattern(DialogMatches.AtMentionMatch2)]
134 | [RegexPattern(DialogMatches.AtMentionMatch3)]
135 | [ScorableGroup(1)]
136 | public void AtMentionMatchUser(IDialogContext context, IActivity activity)
137 | {
138 | context.Call(new AtMentionDialog(), this.EndDialog);
139 | }
140 |
141 | #endregion
142 |
143 | #region Multi Dialog1
144 | [RegexPattern(DialogMatches.MultiDialog1Match1)]
145 | [ScorableGroup(1)]
146 | public void MultiDialog(IDialogContext context, IActivity activity)
147 | {
148 | context.Call(new MultiDialog1(), this.EndDialog);
149 | }
150 |
151 | #endregion
152 |
153 | #region Multi Dialog2
154 | [RegexPattern(DialogMatches.MultiDialog2Match)]
155 | [ScorableGroup(1)]
156 | public void MultiDialog2(IDialogContext context, IActivity activity)
157 | {
158 | context.Call(new MultiDialog2(), this.EndDialog);
159 | }
160 |
161 | #endregion
162 |
163 | #region Help Dialog
164 |
165 | [RegexPattern(DialogMatches.Help)]
166 | [ScorableGroup(1)]
167 | public void Help(IDialogContext context, IActivity activity)
168 | {
169 | this.Default(context, activity);
170 | }
171 |
172 | [MethodBind]
173 | [ScorableGroup(2)]
174 | public void Default(IDialogContext context, IActivity activity)
175 | {
176 | context.Call(new HelpDialog(), this.EndDefaultDialog);
177 | }
178 |
179 | public Task EndDefaultDialog(IDialogContext context, IAwaitable result)
180 | {
181 | context.Done(null);
182 | return Task.CompletedTask;
183 | }
184 |
185 | public Task EndDialog(IDialogContext context, IAwaitable result)
186 | {
187 | context.Done(null);
188 | return Task.CompletedTask;
189 | }
190 |
191 | #endregion
192 |
193 | #region Fetch Last Exceuted Dialog
194 |
195 | [RegexPattern(DialogMatches.FecthLastExecutedDialogMatch)]
196 | [ScorableGroup(1)]
197 | public void FetchLastExecutedDialog(IDialogContext context, IActivity activity)
198 | {
199 | context.Call(new GetLastDialogUsedDialog(), this.EndDialog);
200 | }
201 |
202 | #endregion
203 |
204 | #region Send 1:1 Bot Conversation
205 |
206 | [RegexPattern(DialogMatches.Send1to1Conversation)]
207 | [ScorableGroup(1)]
208 | public async Task SendOneToOneConversation(IDialogContext context, IActivity activity)
209 | {
210 | await context.PostAsync(Strings.Send1on1ConfirmMsg);
211 | context.Call(new ProactiveMsgTo1to1Dialog(), this.EndDialog);
212 | }
213 |
214 | #endregion
215 |
216 | #region Set Up Text Message
217 |
218 | [RegexPattern(DialogMatches.SetUpTextMsg)]
219 | [ScorableGroup(1)]
220 | public void SetUpTextMessage(IDialogContext context, IActivity activity)
221 | {
222 | context.Call(new UpdateTextMsgSetupDialog(), this.EndDialog);
223 | }
224 |
225 | #endregion
226 |
227 | #region Update Last Setup Text Message
228 |
229 | [RegexPattern(DialogMatches.UpdateLastSetupTextMsg)]
230 | [ScorableGroup(1)]
231 | public void UpdateLastSetUpTextMessage(IDialogContext context, IActivity activity)
232 | {
233 | context.Call(new UpdateTextMsgDialog(), this.EndDialog);
234 | }
235 |
236 | #endregion
237 |
238 | #region Set Up & Update Card
239 |
240 | [RegexPattern(DialogMatches.SetUpCardMsg)]
241 | [ScorableGroup(1)]
242 | public void SetUpCardMessage(IDialogContext context, IActivity activity)
243 | {
244 | context.Call(new UpdateCardMsgSetupDialog(), this.EndDialog);
245 | }
246 |
247 | [RegexPattern(DialogMatches.UpdateCard)]
248 | [ScorableGroup(1)]
249 | public void UpdateCardMessage(IDialogContext context, IActivity activity)
250 | {
251 | context.Call(new UpdateCardMsgDialog(), this.EndDialog);
252 | }
253 |
254 | #endregion
255 |
256 | #region Load Different Types of Cards
257 |
258 | [RegexPattern(DialogMatches.DisplayCards)]
259 | [ScorableGroup(1)]
260 | public void DisplayCards(IDialogContext context, IActivity activity)
261 | {
262 | context.Call(new DisplayCardsDialog(), this.EndDialog);
263 | }
264 |
265 | [RegexPattern(DialogMatches.StopShowingCards)]
266 | [ScorableGroup(1)]
267 | public async Task LoadNone(IDialogContext context, IActivity activity)
268 | {
269 | await context.PostAsync(Strings.DisplayCardsThanksMsg);
270 | }
271 |
272 | #endregion
273 |
274 | #region MessageBack Dialog
275 |
276 | [RegexPattern(DialogMatches.MessageBack)]
277 | [ScorableGroup(1)]
278 | public void RunMessageBackDialog(IDialogContext context, IActivity activity)
279 | {
280 | context.Call(new MessagebackDialog(), this.EndDialog);
281 | }
282 |
283 | #endregion
284 |
285 | #region LocalTime
286 |
287 | [RegexPattern(DialogMatches.LocalTime)]
288 | [ScorableGroup(1)]
289 | public async Task GetLocalTimeZone(IDialogContext context, IActivity activity)
290 | {
291 | await context.PostAsync(Strings.UTCTimeZonePrompt + activity.Timestamp);
292 | await context.PostAsync(Strings.LocalTimeZonePrompt + activity.LocalTimestamp);
293 | }
294 |
295 | #endregion
296 |
297 | #region Deeplink Dialog
298 |
299 | [RegexPattern(DialogMatches.DeepLinkTabCard)]
300 | [ScorableGroup(1)]
301 | public void DeeplinkDialog(IDialogContext context, IActivity activity)
302 | {
303 | context.Call(new DeepLinkStaticTabDialog(), this.EndDialog);
304 | }
305 |
306 | #endregion
307 |
308 | #region Authentication Dialog
309 |
310 | [RegexPattern(DialogMatches.AuthSample)]
311 | [ScorableGroup(1)]
312 | public async Task AuthSample(IDialogContext context, IActivity activity)
313 | {
314 | var message = CreateAuthSampleMessage(context);
315 | await context.PostAsync(message);
316 | }
317 |
318 | #region Create Auth Message Card
319 | private IMessageActivity CreateAuthSampleMessage(IDialogContext context)
320 | {
321 | var message = context.MakeMessage();
322 | var attachment = CreateAuthSampleCard();
323 | message.Attachments.Add(attachment);
324 | return message;
325 | }
326 |
327 | private Attachment CreateAuthSampleCard()
328 | {
329 | return new HeroCard
330 | {
331 | Title = Strings.AuthSampleCardTitle,
332 | Buttons = new List
333 | {
334 | new CardAction(ActionTypes.ImBack, Strings.FBAuthCardCaption, value: Strings.FBAuthCardValue),
335 | new CardAction(ActionTypes.ImBack, Strings.VSTSAuthCardCaption, value: Strings.VSTSAuthCardValue)
336 | }
337 | }.ToAttachment();
338 | }
339 | #endregion
340 |
341 | #endregion
342 |
343 | #region Facebook Authentication Exmaple Dialog
344 |
345 | [RegexPattern(DialogMatches.Facebooklogin)]
346 | [ScorableGroup(1)]
347 | public void SimpleFacebookAuthLoginDialog(IDialogContext context, IActivity activity)
348 | {
349 | context.Call(new SimpleFacebookAuthDialog(), this.EndDialog);
350 | }
351 |
352 | [RegexPattern(DialogMatches.Facebooklogout)]
353 | [ScorableGroup(1)]
354 | public async Task SimpleFacebookAuthLogoutDialog(IDialogContext context, IActivity activity)
355 | {
356 | context.PrivateConversationData.RemoveValue(SimpleFacebookAuthDialog.AuthTokenKey);
357 | context.PrivateConversationData.RemoveValue("persistedCookie");
358 | context.UserData.RemoveValue("name");
359 | await context.PostAsync(Strings.FBSuccessfulLogoutPrompt);
360 | await context.PostAsync(Strings.FBSuccessfulLogoutLoginPrompt);
361 | }
362 |
363 | #endregion
364 |
365 | #region VSTS Authentication Exmaple Dialog
366 |
367 | [RegexPattern(DialogMatches.VSTSlogin)]
368 | [ScorableGroup(1)]
369 | public void VSTSAuthLoginDialog(IDialogContext context, IActivity activity)
370 | {
371 | context.Call(new VSTSAPICallDialog(), this.EndDialog);
372 | }
373 |
374 | [RegexPattern(DialogMatches.VSTSlogout)]
375 | [ScorableGroup(1)]
376 | public async Task VSTSAuthLogoutDialog(IDialogContext context, IActivity activity)
377 | {
378 | context.UserData.RemoveValue(VSTSAPICallDialog.VSTSAuthTokenKey);
379 | context.UserData.RemoveValue("persistedCookieVSTS");
380 | context.UserData.RemoveValue("name");
381 | await context.PostAsync(Strings.VSTSSuccessfulLogoutPrompt);
382 | await context.PostAsync(Strings.VSTSSuccessfulLogoutLoginPrompt);
383 | }
384 |
385 | #endregion
386 |
387 | #region VSTS Get Work Item Dialog
388 |
389 | [RegexPattern(DialogMatches.VSTSApi)]
390 | [ScorableGroup(1)]
391 | public void VSTSAuthGetWorkItemDialog(IDialogContext context, IActivity activity)
392 | {
393 | context.Call(new VSTSGetworkItemDialog(), this.EndDialog);
394 | }
395 |
396 | #endregion
397 |
398 | #region Load Hero Card Type
399 |
400 | [RegexPattern(DialogMatches.HeroCard)]
401 | [ScorableGroup(1)]
402 | public void HeroCard(IDialogContext context, IActivity activity)
403 | {
404 | context.Call(new HeroCardDialog(), this.EndDialog);
405 | }
406 |
407 | #endregion
408 |
409 | #region Load Thumbnail Card Type
410 |
411 | [RegexPattern(DialogMatches.ThumbnailCard)]
412 | [ScorableGroup(1)]
413 | public void ThumbnailCard(IDialogContext context, IActivity activity)
414 | {
415 | context.Call(new ThumbnailcardDialog(), this.EndDialog);
416 | }
417 |
418 | #endregion
419 |
420 | #region Load O365Connector Actionable Card Default
421 | [RegexPattern(DialogMatches.O365ConnectorCardActionableCardDefault)]
422 | [ScorableGroup(1)]
423 | public void O365ConnectorCardActionableMessageDefault(IDialogContext context, IActivity activity)
424 | {
425 | context.Call(new O365ConnectorCardActionsDialog(), this.EndDialog);
426 | }
427 | #endregion
428 |
429 | #region Load O365Connector Actionable Card Samples
430 | [RegexPattern(DialogMatches.O365ConnectorCardActionableCards)]
431 | [ScorableGroup(1)]
432 | public void O365ConnectorCardActionableMessage(IDialogContext context, IActivity activity)
433 | {
434 | context.Call(new O365ConnectorCardActionsDialog(), this.EndDialog);
435 | }
436 | #endregion
437 |
438 | #region Load O365Connector Card Default
439 | [RegexPattern(DialogMatches.O365ConnectorCardDefault)]
440 | [ScorableGroup(1)]
441 | public void O365ConnectorCardDefault(IDialogContext context, IActivity activity)
442 | {
443 | context.Call(new O365ConnectorCardDialog(), this.EndDialog);
444 | }
445 | #endregion
446 |
447 | #region Load O365Connector Card Samples
448 | [RegexPattern(DialogMatches.O365ConnectorCards)]
449 | [ScorableGroup(1)]
450 | public void O365ConnectorCard(IDialogContext context, IActivity activity)
451 | {
452 | context.Call(new O365ConnectorCardDialog(), this.EndDialog);
453 | }
454 | #endregion
455 |
456 | #region PopUp SignIn
457 |
458 | [RegexPattern(DialogMatches.PopUpSignIn)]
459 | [ScorableGroup(1)]
460 | public void PopUpSignIn(IDialogContext context, IActivity activity)
461 | {
462 | context.Call(new PopupSigninCardDialog(), this.EndDialog);
463 | }
464 |
465 | #endregion
466 |
467 | #region Team Info
468 |
469 | [RegexPattern(DialogMatches.TeamInfo)]
470 | [ScorableGroup(1)]
471 | public void TeamsInfo(IDialogContext context, IActivity activity)
472 | {
473 | context.Call(new FetchTeamsInfoDialog(), this.EndDialog);
474 | }
475 |
476 | #endregion
477 |
478 | #region Adaptive Card
479 |
480 | [RegexPattern(DialogMatches.AdaptiveCard)]
481 | [ScorableGroup(1)]
482 | public void AdaptiveCard(IDialogContext context, IActivity activity)
483 | {
484 | context.Call(new AdaptiveCardDialog(), this.EndDialog);
485 | }
486 |
487 | #endregion
488 | }
489 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/facebook/FacebookHelpers.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using Newtonsoft.Json;
4 | using System;
5 | using System.Configuration;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Web;
10 |
11 | namespace Microsoft.Teams.TemplateBotCSharp
12 | {
13 |
14 | ///
15 | /// Entity Class to store the Access Token for Auth Flow
16 | ///
17 | public class FacebookAcessToken
18 | {
19 | public FacebookAcessToken()
20 | {
21 | }
22 |
23 | [JsonProperty(PropertyName = "access_token")]
24 | public string AccessToken { get; set; }
25 |
26 | [JsonProperty(PropertyName = "token_type")]
27 | public string TokenType { get; set; }
28 |
29 | [JsonProperty(PropertyName = "expires_in")]
30 | public long ExpiresIn { get; set; }
31 | }
32 |
33 | ///
34 | /// Entity Class to store the User Profile information
35 | ///
36 | public class FacebookProfile
37 | {
38 | public FacebookProfile()
39 | {
40 | }
41 |
42 | [JsonProperty(PropertyName = "id")]
43 | public string Id { get; set; }
44 | [JsonProperty(PropertyName = "name")]
45 | public string Name { get; set; }
46 |
47 | [JsonProperty(PropertyName = "gender")]
48 | public string Gender { get; set; }
49 |
50 | [JsonProperty(PropertyName = "picture")]
51 | public Picture ProfilePicture { get; set; }
52 |
53 | [JsonProperty(PropertyName = "link")]
54 | public string link { get; set; }
55 |
56 | public class Data
57 | {
58 | public bool is_silhouette { get; set; }
59 | public string url { get; set; }
60 | }
61 |
62 | public class Picture
63 | {
64 | public Data data { get; set; }
65 | }
66 | }
67 |
68 | ///
69 | /// Helper class for implementing Facebook API calls.
70 | ///
71 | public static class FacebookHelpers
72 | {
73 | // The Facebook App Id
74 | public static readonly string FacebookAppId = ConfigurationManager.AppSettings["FBAppId"].ToString();
75 |
76 | // The Facebook App Secret
77 | public static readonly string FacebookAppSecret = ConfigurationManager.AppSettings["FBAppSecret"].ToString();
78 |
79 | ///
80 | /// Get the Authentication Token from Api code
81 | ///
82 | ///
83 | ///
84 | ///
85 | ///
86 | public async static Task ExchangeCodeForAccessToken(ConversationReference conversationReference, string code, string facebookOauthCallback)
87 | {
88 | var redirectUri = GetOAuthCallBack(conversationReference, facebookOauthCallback);
89 | var uri = GetUri(ConfigurationManager.AppSettings["FBTokenUrl"].ToString(),
90 | Tuple.Create("client_id", FacebookAppId),
91 | Tuple.Create("redirect_uri", redirectUri),
92 | Tuple.Create("client_secret", FacebookAppSecret),
93 | Tuple.Create("code", code)
94 | );
95 |
96 | return await FacebookRequest(uri);
97 | }
98 |
99 | ///
100 | /// Validate the Access Token
101 | ///
102 | ///
103 | ///
104 | public static async Task ValidateAccessToken(string accessToken)
105 | {
106 | var uri = GetUri(ConfigurationManager.AppSettings["FBDebugUrl"].ToString(),
107 | Tuple.Create("input_token", accessToken),
108 | Tuple.Create("access_token", $"{FacebookAppId}|{FacebookAppSecret}"));
109 |
110 | var res = await FacebookRequest(uri).ConfigureAwait(false);
111 | return (((dynamic)res)?.data)?.is_valid;
112 | }
113 |
114 | ///
115 | /// Get the User Profile information using valid Access Token
116 | ///
117 | ///
118 | ///
119 | public static async Task GetFacebookProfileName(string accessToken)
120 | {
121 | var uri = GetUri(ConfigurationManager.AppSettings["FBProfileUrl"].ToString(),
122 | Tuple.Create("fields", "id,name,gender,picture,link"),
123 | Tuple.Create("access_token", accessToken));
124 |
125 | var res = await FacebookRequest(uri);
126 |
127 | return res;
128 | }
129 |
130 | ///
131 | /// Get the Profile Picture detail using valid Access Token
132 | ///
133 | ///
134 | ///
135 | public static async Task GetFacebookProfilePicture(string accessToken)
136 | {
137 | var uri = GetUri("https://graph.facebook.com/v2.10/me/picture?width=200&height=200",
138 | Tuple.Create("access_token", accessToken));
139 | var res = await FacebookRequest(uri);
140 | return res;
141 | }
142 |
143 | ///
144 | /// Create the Auth URL
145 | ///
146 | ///
147 | ///
148 | ///
149 | private static string GetOAuthCallBack(ConversationReference conversationReference, string facebookOauthCallback)
150 | {
151 | var uri = GetUri(facebookOauthCallback,
152 | Tuple.Create("userId", TokenEncoder(conversationReference.User.Id)),
153 | Tuple.Create("botId", TokenEncoder(conversationReference.Bot.Id)),
154 | Tuple.Create("conversationId", TokenEncoder(conversationReference.Conversation.Id)),
155 | Tuple.Create("serviceUrl", TokenEncoder(conversationReference.ServiceUrl)),
156 | Tuple.Create("channelId", conversationReference.ChannelId)
157 | );
158 | return uri.ToString();
159 | }
160 |
161 | ///
162 | /// Create Facebook Login URL
163 | ///
164 | ///
165 | ///
166 | ///
167 | public static string GetFacebookLoginURL(ConversationReference conversationReference, string facebookOauthCallback)
168 | {
169 | var redirectUri = GetOAuthCallBack(conversationReference, facebookOauthCallback);
170 | var uri = GetUri(ConfigurationManager.AppSettings["FBAuthUrl"].ToString(),
171 | Tuple.Create("client_id", FacebookAppId),
172 | Tuple.Create("redirect_uri", redirectUri),
173 | Tuple.Create("response_type", "code"),
174 | Tuple.Create("scope", "public_profile,email"),
175 | Tuple.Create("state", Convert.ToString(new Random().Next(9999)))
176 | );
177 |
178 | return uri.ToString();
179 | }
180 |
181 | ///
182 | /// Purpose of this request is to process the Api Calls
183 | ///
184 | ///
185 | ///
186 | ///
187 | private static async Task FacebookRequest(Uri uri)
188 | {
189 | string json;
190 | using (HttpClient client = new HttpClient())
191 | {
192 | json = await client.GetStringAsync(uri).ConfigureAwait(false);
193 | }
194 |
195 | try
196 | {
197 | var result = JsonConvert.DeserializeObject(json);
198 | return result;
199 | }
200 | catch (JsonException ex)
201 | {
202 | throw new ArgumentException(Strings.FBAuthDeserializeError, ex);
203 | }
204 | }
205 |
206 | ///
207 | /// Helper method to create URL
208 | ///
209 | ///
210 | ///
211 | ///
212 | private static Uri GetUri(string endPoint, params Tuple[] queryParams)
213 | {
214 | var queryString = HttpUtility.ParseQueryString(string.Empty);
215 | foreach (var queryparam in queryParams)
216 | {
217 | queryString[queryparam.Item1] = queryparam.Item2;
218 | }
219 |
220 | var builder = new UriBuilder(endPoint);
221 | builder.Query = queryString.ToString();
222 | return builder.Uri;
223 | }
224 |
225 | // because of a limitation on the characters in Facebook redirect_uri, we don't use the serialization of the cookie.
226 | // http://stackoverflow.com/questions/4386691/facebook-error-error-validating-verification-code
227 | public static string TokenEncoder(string token)
228 | {
229 | return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(token));
230 | }
231 |
232 | public static string TokenDecoder(string token)
233 | {
234 | return Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token));
235 | }
236 |
237 |
238 | }
239 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/facebook/OAuthCallbackController.cs:
--------------------------------------------------------------------------------
1 | using Autofac;
2 | using Microsoft.Bot.Builder.ConnectorEx;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using Microsoft.Bot.Builder.Dialogs.Internals;
5 | using Microsoft.Bot.Connector;
6 | using Microsoft.Teams.TemplateBotCSharp.Properties;
7 | using System;
8 | using System.Configuration;
9 | using System.Net;
10 | using System.Net.Http;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 | using System.Web.Http;
14 |
15 | namespace Microsoft.Teams.TemplateBotCSharp
16 | {
17 | public class OAuthCallbackController : ApiController
18 | {
19 | ///
20 | /// Facebook OAuth Callback Method
21 | ///
22 | /// The Id for the user that is getting authenticated.
23 | /// Bot Id.
24 | /// The Id of the conversation.
25 | /// The Id of the channel.
26 | /// The Id of the Teams Service url.
27 | /// The Authentication code returned by Facebook.
28 | /// The state returned by Facebook.
29 | ///
30 | [HttpGet]
31 | [Route("api/OAuthCallback")]
32 | public async Task OAuthCallback([FromUri] string userId, [FromUri] string botId, [FromUri] string conversationId, [FromUri] string channelId, [FromUri] string serviceUrl, [FromUri] string code, [FromUri] string state, CancellationToken token)
33 | {
34 | // Get the resumption cookie
35 | var address = new Address
36 | (
37 | // purposefully using named arguments because these all have the same type
38 | botId: FacebookHelpers.TokenDecoder(botId),
39 | channelId: channelId,
40 | userId: FacebookHelpers.TokenDecoder(userId),
41 | conversationId: FacebookHelpers.TokenDecoder(conversationId),
42 | serviceUrl: FacebookHelpers.TokenDecoder(serviceUrl)
43 | );
44 |
45 | var conversationReference = address.ToConversationReference();
46 |
47 | // Exchange the Facebook Auth code with Access token
48 | var accessToken = await FacebookHelpers.ExchangeCodeForAccessToken(conversationReference, code, SimpleFacebookAuthDialog.FacebookOauthCallback.ToString());
49 |
50 | //Set the User Token, Magic Number and IsValidated Property to User Properties.
51 | conversationReference.User.Properties.Add(ConfigurationManager.AppSettings["FBAccessTokenKey"].ToString(), accessToken.AccessToken);
52 | conversationReference.User.Properties.Add(ConfigurationManager.AppSettings["FBMagicNumberKey"].ToString(), ConfigurationManager.AppSettings["FBMagicNumberValue"].ToString());
53 | conversationReference.User.Properties.Add(ConfigurationManager.AppSettings["FBIsValidatedKey"].ToString(), false);
54 |
55 | // Create the message that is send to conversation to resume the login flow
56 | var msg = conversationReference.GetPostToBotMessage();
57 | msg.Text = $"token:{accessToken.AccessToken}";
58 |
59 | // Resume the conversation to SimpleFacebookAuthDialog
60 | using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, msg))
61 | {
62 | var dataBag = scope.Resolve();
63 | await dataBag.LoadAsync(token);
64 |
65 | ConversationReference pending;
66 | var connector = new ConnectorClient(new Uri(conversationReference.ServiceUrl));
67 |
68 | if (dataBag.PrivateConversationData.TryGetValue("persistedCookie", out pending))
69 | {
70 | dataBag.PrivateConversationData.SetValue("persistedCookie", conversationReference);
71 |
72 | await dataBag.FlushAsync(token);
73 |
74 | //Send message to Bot
75 | IMessageActivity message = Activity.CreateMessageActivity();
76 | message.From = conversationReference.User;
77 | message.Recipient = conversationReference.User;
78 | message.Conversation = new ConversationAccount(id: conversationReference.Conversation.Id);
79 | message.Text = Strings.OAuthCallbackUserPrompt;
80 | await connector.Conversations.SendToConversationAsync((Activity)message);
81 |
82 | return Request.CreateResponse(Strings.OAuthCallbackMessage);
83 | }
84 | else
85 | {
86 | // Callback is called with no pending message as a result the login flow cannot be resumed.
87 | return Request.CreateErrorResponse(HttpStatusCode.BadRequest, new InvalidOperationException(Strings.AuthCallbackResumeError));
88 | }
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/facebook/SimpleFacebookAuthDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.ConnectorEx;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Configuration;
8 | using System.Threading.Tasks;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp
11 | {
12 | ///
13 | /// This Dialog implements the OAuth login flow for Facebook.
14 | /// You can read more about Facebook's login flow here: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
15 | ///
16 | [Serializable]
17 | public class SimpleFacebookAuthDialog : IDialog
18 | {
19 |
20 | ///
21 | /// OAuth callback registered for Facebook app.
22 | /// implementats the callback.
23 | ///
24 | ///
25 | /// Make sure to replace this with the appropriate website url registered for your Facebook app.
26 | ///
27 | public static readonly Uri FacebookOauthCallback = new Uri(ConfigurationManager.AppSettings["FBCallbackUrl"].ToString());
28 |
29 | ///
30 | /// The key that is used to keep the AccessToken in
31 | ///
32 | public static readonly string AuthTokenKey = ConfigurationManager.AppSettings["FBAuthToken"].ToString();
33 |
34 | public async Task StartAsync(IDialogContext context)
35 | {
36 | //Set the Last Dialog in Conversation Data
37 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFacebookDialog);
38 |
39 | await LogIn(context);
40 | }
41 |
42 | public async virtual Task MessageReceivedAsync(IDialogContext context, IAwaitable argument)
43 | {
44 | var msg = await (argument);
45 | ConversationReference conversationReference;
46 | FacebookAcessToken facebookToken = new FacebookAcessToken();
47 | string magicNumber = string.Empty;
48 | string token = string.Empty;
49 |
50 | if (context.PrivateConversationData.TryGetValue("persistedCookie", out conversationReference))
51 | {
52 | magicNumber = conversationReference.User.Properties[ConfigurationManager.AppSettings["FBMagicNumberKey"].ToString()].ToString();
53 |
54 | if (string.Equals(msg.Text, magicNumber))
55 | {
56 | conversationReference.User.Properties[ConfigurationManager.AppSettings["FBIsValidatedKey"].ToString()] = true;
57 | context.PrivateConversationData.SetValue("persistedCookie", conversationReference);
58 |
59 | token = conversationReference.User.Properties[ConfigurationManager.AppSettings["FBAccessTokenKey"].ToString()].ToString();
60 |
61 | var valid = await FacebookHelpers.ValidateAccessToken(token);
62 |
63 | if(valid)
64 | {
65 | FacebookProfile profile = await FacebookHelpers.GetFacebookProfileName(token);
66 | var message = CreateFBMessage(context, profile);
67 |
68 | await context.PostAsync(message);
69 | await context.PostAsync(Strings.FBLginSuccessPromptLogoutInfo);
70 |
71 | context.PrivateConversationData.SetValue(AuthTokenKey, token);
72 | context.Done(token);
73 | }
74 | }
75 | else
76 | {
77 | //When entered number is not valid
78 | await context.PostAsync(Strings.AuthMagicNumberNotMacthed);
79 | await LogIn(context);
80 | }
81 | }
82 | else
83 | {
84 | await LogIn(context);
85 | }
86 | }
87 |
88 | #region Create FB Profile Message Card
89 | private Attachment CreateFBProfileCard(FacebookProfile profile)
90 | {
91 | return new ThumbnailCard
92 | {
93 | Title = Strings.FBLoginSuccessPrompt + " " + profile.Name + "(" + profile.Gender + ")",
94 | Images = new List { new CardImage(profile.ProfilePicture.data.url) },
95 | Buttons = new List
96 | {
97 | new CardAction(ActionTypes.OpenUrl, Strings.FBCardButtonCaption, value: profile.link)
98 | }
99 | }.ToAttachment();
100 | }
101 |
102 | private IMessageActivity CreateFBMessage(IDialogContext context, FacebookProfile profile)
103 | {
104 | var message = context.MakeMessage();
105 | var attachment = CreateFBProfileCard(profile);
106 | message.Attachments.Add(attachment);
107 | return message;
108 | }
109 | #endregion
110 |
111 | ///
112 | /// Login the user.
113 | ///
114 | /// The Dialog context.
115 | /// A task that represents the login action.
116 | private async Task LogIn(IDialogContext context)
117 | {
118 | string token;
119 | if (!context.PrivateConversationData.TryGetValue(AuthTokenKey, out token))
120 | {
121 | var conversationReference = context.Activity.ToConversationReference();
122 |
123 | context.PrivateConversationData.SetValue("persistedCookie", conversationReference);
124 |
125 | // sending the sigin card with Facebook login url
126 | var reply = context.MakeMessage();
127 | var fbLoginUrl = FacebookHelpers.GetFacebookLoginURL(conversationReference, FacebookOauthCallback.ToString());
128 | reply.Text = Strings.FBLoginTitle;
129 |
130 | //Login Card
131 | var loginCard = new HeroCard
132 | {
133 | Title = Strings.FBLoginCardPrompt,
134 | Buttons = new List { new CardAction(ActionTypes.OpenUrl, Strings.FBLoginCardButtonCaption, value: fbLoginUrl) }
135 | };
136 |
137 | reply.Attachments.Add(loginCard.ToAttachment());
138 |
139 | await context.PostAsync(reply);
140 | context.Wait(MessageReceivedAsync);
141 | }
142 | else
143 | {
144 | await context.PostAsync(Strings.FBLoginSessionExistsPrompt);
145 | await context.PostAsync(Strings.FBLogoutPrompt);
146 | context.Done(token);
147 | }
148 | }
149 | }
150 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/vsts/OAuthCallbackVSTSController.cs:
--------------------------------------------------------------------------------
1 | using Autofac;
2 | using Microsoft.Bot.Builder.ConnectorEx;
3 | using Microsoft.Bot.Builder.Dialogs;
4 | using Microsoft.Bot.Builder.Dialogs.Internals;
5 | using Microsoft.Bot.Connector;
6 | using Microsoft.Teams.TemplateBotCSharp.Properties;
7 | using Newtonsoft.Json;
8 | using System;
9 | using System.Configuration;
10 | using System.Net;
11 | using System.Net.Http;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 | using System.Web.Http;
15 |
16 | namespace Microsoft.Teams.TemplateBotCSharp
17 | {
18 | public class OAuthCallbackVSTSController : ApiController
19 | {
20 | ///
21 | /// OAuth call back that is called by VSTS. Read https://www.visualstudio.com/en-us/docs/integrate/extensions/overview for more details.
22 | ///
23 | /// The Authentication code returned by VSTS.
24 | /// The state returned by VSTS.
25 | ///
26 | [HttpGet]
27 | [Route("api/OAuthCallbackVSTS")]
28 | public async Task OAuthCallbackVSTS(string code, string state, CancellationToken token)
29 | {
30 | ConversationReference conversationReferenceJSON = JsonConvert.DeserializeObject(state);
31 |
32 | //// Get the resumption cookie
33 | var address = new Address
34 | (
35 | botId: conversationReferenceJSON.Bot.Id,
36 | channelId: conversationReferenceJSON.ChannelId,
37 | userId: conversationReferenceJSON.User.Id,
38 | conversationId: conversationReferenceJSON.Conversation.Id,
39 | serviceUrl: conversationReferenceJSON.ServiceUrl
40 | );
41 |
42 | var conversationReference = address.ToConversationReference();
43 |
44 | string workItemId = string.Empty;
45 |
46 | if (conversationReferenceJSON.User.Properties["workItemId"] != null)
47 | {
48 | workItemId = conversationReferenceJSON.User.Properties["workItemId"].ToString();
49 | conversationReference.User.Properties.Add("workItemId", workItemId);
50 | }
51 |
52 | VSTSAcessToken accessToken = new VSTSAcessToken();
53 | String error = null;
54 |
55 | if (!String.IsNullOrEmpty(code))
56 | {
57 | error = VSTSHelpers.PerformTokenRequest(VSTSHelpers.GenerateRequestPostData(code), true, out accessToken);
58 |
59 | //Set the User Token, Magic Number and IsValidated Property to User Properties.
60 | if (String.IsNullOrEmpty(error))
61 | {
62 | conversationReference.User.Properties.Add("AccessToken", accessToken.accessToken);
63 | conversationReference.User.Properties.Add("RefreshToken", accessToken.refreshToken);
64 | conversationReference.User.Properties.Add("MagicNumber", ConfigurationManager.AppSettings["VSTSMagicNumber"].ToString());
65 | conversationReference.User.Properties.Add("IsValidated", false);
66 | conversationReference.User.Properties.Add("UserName", conversationReferenceJSON.User.Name);
67 | }
68 | else
69 | {
70 | return null;
71 | }
72 | }
73 | else
74 | {
75 | return Request.CreateErrorResponse(HttpStatusCode.BadRequest, new InvalidOperationException(Strings.VSTSCallbackAuthError));
76 | }
77 |
78 | // Create the message that is send to conversation to resume the login flow
79 | var msg = conversationReference.GetPostToBotMessage();
80 | msg.Text = $"token:{accessToken.accessToken}";
81 |
82 | // Resume the conversation to SimpleFacebookAuthDialog
83 | using (var scope1 = DialogModule.BeginLifetimeScope(Conversation.Container, msg))
84 | {
85 | var dataBag = scope1.Resolve();
86 | await dataBag.LoadAsync(token);
87 |
88 | ConversationReference pending;
89 | var connector = new ConnectorClient(new Uri(conversationReference.ServiceUrl));
90 |
91 | if (dataBag.UserData.TryGetValue("persistedCookieVSTS", out pending))
92 | {
93 | dataBag.UserData.SetValue("persistedCookieVSTS", conversationReference);
94 |
95 | await dataBag.FlushAsync(token);
96 |
97 | //Send message to Bot
98 | IMessageActivity message = Activity.CreateMessageActivity();
99 | message.From = conversationReference.User;
100 | message.Recipient = conversationReference.User;
101 | message.Conversation = new ConversationAccount(id: conversationReference.Conversation.Id);
102 | message.Text = Strings.OAuthCallbackUserPrompt;
103 | await connector.Conversations.SendToConversationAsync((Activity)message);
104 |
105 | return Request.CreateResponse(Strings.OAuthCallbackMessage);
106 | }
107 | else
108 | {
109 | // Callback is called with no pending message as a result the login flow cannot be resumed.
110 | return Request.CreateErrorResponse(HttpStatusCode.BadRequest, new InvalidOperationException(Strings.AuthCallbackResumeError));
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/vsts/VSTSAPICallDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.ConnectorEx;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Configuration;
8 | using System.Threading.Tasks;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp
11 | {
12 | ///
13 | /// This Dialog implements the OAuth login flow for VSTS.
14 | /// You can read more about VSTS login flow here: https://www.visualstudio.com/en-us/docs/integrate/extensions/overview
15 | ///
16 | [Serializable]
17 | public class VSTSAPICallDialog : IDialog
18 | {
19 |
20 | ///
21 | /// OAuth callback registered for Facebook app.
22 | /// implementats the callback.
23 | ///
24 | ///
25 | /// Make sure to replace this with the appropriate website url registered for your VSTS app.
26 | ///
27 | public static readonly Uri VSTSOauthCallback = new Uri(ConfigurationManager.AppSettings["CallbackUrl"].ToString());
28 |
29 | ///
30 | /// The key that is used to keep the AccessToken in
31 | ///
32 | public static readonly string VSTSAuthTokenKey = ConfigurationManager.AppSettings["VSTSAuthToken"].ToString();
33 |
34 | public async Task StartAsync(IDialogContext context)
35 | {
36 | //Set the Last Dialog in Conversation Data
37 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogVSTSDialog);
38 |
39 | await LogIn(context);
40 | }
41 |
42 | public async virtual Task MessageReceivedAsync(IDialogContext context, IAwaitable argument)
43 | {
44 | var msg = await (argument);
45 | ConversationReference conversationReference;
46 | VSTSAcessToken facebookToken = new VSTSAcessToken();
47 | string magicNumber = string.Empty;
48 | string token = string.Empty;
49 |
50 | if (context.UserData.TryGetValue("persistedCookieVSTS", out conversationReference))
51 | {
52 | magicNumber = conversationReference.User.Properties["MagicNumber"].ToString();
53 |
54 | if (string.Equals(msg.Text, magicNumber))
55 | {
56 | conversationReference.User.Properties["IsValidated"] = true;
57 |
58 | context.UserData.SetValue("persistedCookieVSTS", conversationReference);
59 |
60 | token = conversationReference.User.Properties["AccessToken"].ToString();
61 |
62 | // Dialog is resumed by the OAuth callback and access token
63 | // is encoded in the message.Text
64 | var valid = Convert.ToBoolean(conversationReference.User.Properties["IsValidated"]);
65 |
66 | if (valid)
67 | {
68 | var name = conversationReference.User.Properties["UserName"].ToString();
69 | context.UserData.SetValue("name", name);
70 | await context.PostAsync(Strings.VSTSLoginSuccessPrompt);
71 | await context.PostAsync(Strings.VSTSlogoutPrompt);
72 | context.UserData.SetValue(VSTSAuthTokenKey, token);
73 | context.Done(token);
74 | }
75 |
76 | }
77 | else
78 | {
79 | //When entered number is not valid
80 | await context.PostAsync(Strings.AuthMagicNumberNotMacthed);
81 | await LogIn(context);
82 | }
83 | }
84 | else
85 | {
86 | await LogIn(context);
87 | }
88 | }
89 |
90 | ///
91 | /// Login the user.
92 | ///
93 | /// The Dialog context.
94 | /// A task that represents the login action.
95 | private async Task LogIn(IDialogContext context)
96 | {
97 | string token;
98 | if (!context.UserData.TryGetValue(VSTSAuthTokenKey, out token))
99 | {
100 | var conversationReference = context.Activity.ToConversationReference();
101 |
102 | context.UserData.SetValue("persistedCookieVSTS", conversationReference);
103 |
104 | // sending the sigin card with Facebook login url
105 | var reply = context.MakeMessage();
106 | var vstsLoginUrl = VSTSHelpers.GenerateAuthorizeUrl(conversationReference);
107 |
108 | reply.Text = Strings.VSTSLoginTitle;
109 |
110 | //Login Card
111 | var loginCard = new HeroCard
112 | {
113 | Title = Strings.VSTSLoginCardTitle,
114 | Buttons = new List { new CardAction(ActionTypes.OpenUrl, Strings.VSTSLoginCardButtonCaption, value: vstsLoginUrl) }
115 | };
116 |
117 | reply.Attachments.Add(loginCard.ToAttachment());
118 |
119 | await context.PostAsync(reply);
120 | context.Wait(MessageReceivedAsync);
121 | }
122 | else
123 | {
124 | await context.PostAsync(Strings.VSTSLoginSessionExistsPrompt);
125 | await context.PostAsync(Strings.VSTSlogoutPrompt);
126 | context.Done(token);
127 | }
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/vsts/VSTSGetworkItemDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.ConnectorEx;
2 | using Microsoft.Bot.Builder.Dialogs;
3 | using Microsoft.Bot.Connector;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Configuration;
8 | using System.Threading.Tasks;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp
11 | {
12 | ///
13 | /// This Dialog implements the OAuth login flow for Facebook.
14 | /// You can read more about Facebook's login flow here: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
15 | ///
16 | [Serializable]
17 | public class VSTSGetworkItemDialog : IDialog
18 | {
19 |
20 | ///
21 | /// The key that is used to keep the AccessToken in
22 | ///
23 | public static readonly string VSTSAuthTokenKey = ConfigurationManager.AppSettings["VSTSAuthToken"].ToString();
24 |
25 | public async Task StartAsync(IDialogContext context)
26 | {
27 | await context.PostAsync(Strings.VSTSGetWorkItemPrompt);
28 | context.Wait(this.MessageReceivedAsync);
29 | }
30 |
31 | public async virtual Task MessageReceivedAsync(IDialogContext context, IAwaitable argument)
32 | {
33 | var msg = await (argument);
34 |
35 | ConversationReference conversationReference;
36 | VSTSAcessToken vstsToken = new VSTSAcessToken();
37 | string magicNumber = string.Empty;
38 | string token = string.Empty;
39 | string refreshToken = string.Empty;
40 | String error = null;
41 | string requestedWorkItemId = string.Empty;
42 | bool IsAuthenticated = false;
43 |
44 | if (context.UserData.TryGetValue("persistedCookieVSTS", out conversationReference))
45 | {
46 | requestedWorkItemId = conversationReference.User.Properties["workItemId"].ToString();
47 |
48 | if(string.IsNullOrEmpty(requestedWorkItemId))
49 | {
50 | requestedWorkItemId = msg.Text;
51 | IsAuthenticated = true;
52 | }
53 | else
54 | {
55 | magicNumber = conversationReference.User.Properties["MagicNumber"].ToString();
56 |
57 | if (string.Equals(msg.Text, magicNumber))
58 | {
59 | IsAuthenticated = true;
60 | }
61 | else
62 | {
63 | //When entered number is not valid
64 | await context.PostAsync(Strings.AuthMagicNumberNotMacthed);
65 | await LogIn(context, msg.Text);
66 | }
67 | }
68 |
69 | if (IsAuthenticated)
70 | {
71 | refreshToken = conversationReference.User.Properties["RefreshToken"].ToString();
72 |
73 | //Get the refreshed token
74 | error = VSTSHelpers.PerformTokenRequest(VSTSHelpers.GenerateRefreshPostData(refreshToken), true, out vstsToken);
75 |
76 | if (String.IsNullOrEmpty(error))
77 | {
78 | conversationReference.User.Properties["AccessToken"] = vstsToken.accessToken;
79 | conversationReference.User.Properties["RefreshToken"] = vstsToken.refreshToken;
80 | }
81 |
82 | WorkItem workItem = await VSTSHelpers.GetWorkItem(vstsToken.accessToken, requestedWorkItemId);
83 |
84 | if (workItem != null)
85 | {
86 | var workItemCardMessage = CreateWorkItemCard(context, workItem, requestedWorkItemId);
87 | await context.PostAsync(workItemCardMessage);
88 | }
89 | }
90 | }
91 | else
92 | {
93 | await LogIn(context, msg.Text);
94 | }
95 | }
96 |
97 | ///
98 | /// Login the user.
99 | ///
100 | /// The Dialog context.
101 | /// A task that represents the login action.
102 | private async Task LogIn(IDialogContext context, string workItemId)
103 | {
104 | string token;
105 | if (!context.UserData.TryGetValue(VSTSAuthTokenKey, out token))
106 | {
107 | var conversationReference = context.Activity.ToConversationReference();
108 |
109 | context.UserData.SetValue("persistedCookieVSTS", conversationReference);
110 | conversationReference.User.Properties.Add("workItemId", workItemId);
111 |
112 | // sending the sigin card with Facebook login url
113 | var reply = context.MakeMessage();
114 | var vstsLoginUrl = VSTSHelpers.GenerateAuthorizeUrl(conversationReference);
115 |
116 | reply.Text = Strings.VSTSGetWorkItemLoginPrompt;
117 |
118 | //Login Card
119 |
120 | var loginCard = new HeroCard
121 | {
122 | Title = Strings.VSTSLoginCardTitle,
123 | Buttons = new List { new CardAction(ActionTypes.OpenUrl, Strings.VSTSLoginCardButtonCaption, value: vstsLoginUrl) }
124 | };
125 |
126 | reply.Attachments.Add(loginCard.ToAttachment());
127 |
128 | await context.PostAsync(reply);
129 | context.Wait(MessageReceivedAsync);
130 | }
131 | else
132 | {
133 | await context.PostAsync(Strings.VSTSLoginSessionExistsPrompt);
134 | await context.PostAsync(Strings.VSTSlogoutPrompt);
135 | context.Done(token);
136 | }
137 | }
138 |
139 | #region Create Work Item Message Card
140 | private Attachment CreateWorkItemAttachment(WorkItem workItem, string workItemId)
141 | {
142 | var encodedUrl = workItem.TeamProject;
143 | string goToWorkItemUrl = "https://teamsbot.visualstudio.com/" + encodedUrl + "/_workitems?id=" + workItemId + "&_a=edit";
144 | return new HeroCard
145 | {
146 | Title = workItem.Title,
147 | Subtitle = workItem.Url,
148 | Buttons = new List
149 | {
150 | new CardAction(ActionTypes.OpenUrl, Strings.VSTSGetWorkItemCardButtonCaption, value: goToWorkItemUrl),
151 | }
152 | }.ToAttachment();
153 | }
154 |
155 | private IMessageActivity CreateWorkItemCard(IDialogContext context, WorkItem workItem, string workItemId)
156 | {
157 | var message = context.MakeMessage();
158 | var attachment = CreateWorkItemAttachment(workItem, workItemId);
159 | message.Attachments.Add(attachment);
160 | return message;
161 | }
162 | #endregion
163 |
164 | }
165 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/auth/vsts/VSTSHelpers.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Linq;
5 | using System;
6 | using System.Configuration;
7 | using System.IO;
8 | using System.Net;
9 | using System.Net.Http;
10 | using System.Threading.Tasks;
11 | using System.Web;
12 |
13 | namespace Microsoft.Teams.TemplateBotCSharp
14 | {
15 | ///
16 | /// This is Entity Class for VSTS Profile Information
17 | ///
18 | class VSTSProfile
19 | {
20 | public VSTSProfile()
21 | {
22 | }
23 |
24 | [JsonProperty(PropertyName = "id")]
25 | public string Id { get; set; }
26 | [JsonProperty(PropertyName = "name")]
27 | public string Name { get; set; }
28 | }
29 |
30 | ///
31 | /// Entity Class to store the Access Token for Auth Flow
32 | ///
33 | public class VSTSAcessToken
34 | {
35 | public VSTSAcessToken()
36 | {
37 |
38 | }
39 |
40 | [JsonProperty(PropertyName = "access_token")]
41 | public String accessToken { get; set; }
42 |
43 | [JsonProperty(PropertyName = "token_type")]
44 | public String tokenType { get; set; }
45 |
46 | [JsonProperty(PropertyName = "expires_in")]
47 | public String expiresIn { get; set; }
48 |
49 | [JsonProperty(PropertyName = "refresh_token")]
50 | public String refreshToken { get; set; }
51 |
52 | }
53 | ///
54 | /// Entity Class to store the Work Item details
55 | ///
56 | public class WorkItem
57 | {
58 | public int Id { get; set; }
59 | public int Rev { get; set; }
60 | public string Title { get; set; }
61 | public string TeamProject { get; set; }
62 | public string Url { get; set; }
63 | }
64 |
65 | public static class VSTSHelpers
66 | {
67 | ///
68 | /// Execute the VSTS Api call
69 | ///
70 | ///
71 | ///
72 | ///
73 | ///
74 | public static String PerformTokenRequest(String postData, bool IsCallback, out VSTSAcessToken token)
75 | {
76 | var error = String.Empty;
77 | var strResponseData = String.Empty;
78 |
79 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(
80 | ConfigurationManager.AppSettings["TokenUrl"]
81 | );
82 |
83 | webRequest.Method = "POST";
84 | webRequest.ContentLength = postData.Length;
85 | webRequest.ContentType = "application/x-www-form-urlencoded";
86 |
87 | using (StreamWriter swRequestWriter = new StreamWriter(webRequest.GetRequestStream()))
88 | {
89 | swRequestWriter.Write(postData);
90 | }
91 |
92 | try
93 | {
94 | HttpWebResponse hwrWebResponse = (HttpWebResponse)webRequest.GetResponse();
95 |
96 | if (hwrWebResponse.StatusCode == HttpStatusCode.OK)
97 | {
98 | using (StreamReader srResponseReader = new StreamReader(hwrWebResponse.GetResponseStream()))
99 | {
100 | strResponseData = srResponseReader.ReadToEnd();
101 | }
102 |
103 | token = JsonConvert.DeserializeObject(strResponseData);
104 | return null;
105 | }
106 | }
107 | catch (WebException wex)
108 | {
109 | error = Strings.VSTSApiRequestError + wex.Message;
110 | }
111 | catch (Exception ex)
112 | {
113 | error = Strings.VSTSApiIssue + ex.Message;
114 | }
115 |
116 | token = new VSTSAcessToken();
117 | return error;
118 | }
119 |
120 | ///
121 | /// Create authorization the url
122 | ///
123 | ///
124 | ///
125 | public static String GenerateAuthorizeUrl(ConversationReference conversationReference)
126 | {
127 | UriBuilder uriBuilder = new UriBuilder(ConfigurationManager.AppSettings["AuthUrl"]);
128 | var queryParams = HttpUtility.ParseQueryString(uriBuilder.Query ?? String.Empty);
129 |
130 | string stateData = JsonConvert.SerializeObject(conversationReference);
131 |
132 | queryParams["client_id"] = ConfigurationManager.AppSettings["AppId"];
133 | queryParams["response_type"] = "Assertion";
134 | queryParams["state"] = stateData;
135 | queryParams["scope"] = ConfigurationManager.AppSettings["Scope"];
136 | queryParams["redirect_uri"] = ConfigurationManager.AppSettings["CallbackUrl"];
137 |
138 | uriBuilder.Query = queryParams.ToString();
139 |
140 | return uriBuilder.ToString();
141 | }
142 |
143 | ///
144 | /// Get the VSTS Profile
145 | ///
146 | ///
147 | ///
148 | public static async Task GetVSTSProfile(string accessToken)
149 | {
150 | var uri = GetUri("https://teamsbot.visualstudio.com/DefaultCollection/_apis/profile/profiles/me");
151 | var res = await VSTSRequestAPI(uri, accessToken);
152 | return res;
153 | }
154 |
155 | ///
156 | /// Get VSTS Work Item
157 | ///
158 | ///
159 | ///
160 | ///
161 | public static async Task GetWorkItem(string accessToken, string workItemId)
162 | {
163 | WorkItem item = new WorkItem();
164 | var uri = GetUri("https://teamsbot.visualstudio.com/DefaultCollection/_apis/wit/workitems?",
165 | //Tuple.Create("access_token", accessToken));
166 | Tuple.Create("id", workItemId),
167 | Tuple.Create("api-version", "1.0"));
168 |
169 | var res = await VSTSRequestAPI(uri, accessToken);
170 |
171 | var jsonObject= JObject.Parse(res); // parse as array
172 |
173 | if (jsonObject != null)
174 | {
175 | item.Title = jsonObject["fields"]["System.Title"].ToString();
176 | item.TeamProject = jsonObject["fields"]["System.TeamProject"].ToString();
177 | item.Url = jsonObject["url"].ToString();
178 | }
179 |
180 | return item;
181 | }
182 |
183 | ///
184 | /// Get Create Api Post Data
185 | ///
186 | ///
187 | ///
188 | public static string GenerateRequestPostData(string code)
189 | {
190 | return string.Format("client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={1}&redirect_uri={2}",
191 | HttpUtility.UrlEncode(ConfigurationManager.AppSettings["AppSecret"]),
192 | HttpUtility.UrlEncode(code),
193 | ConfigurationManager.AppSettings["CallbackUrl"]
194 | );
195 | }
196 |
197 | ///
198 | /// Get the Refresh Token Api Post Data
199 | ///
200 | ///
201 | ///
202 | public static string GenerateRefreshPostData(string refreshToken)
203 | {
204 | return string.Format("client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=refresh_token&assertion={1}&redirect_uri={2}",
205 | HttpUtility.UrlEncode(ConfigurationManager.AppSettings["AppSecret"]),
206 | HttpUtility.UrlEncode(refreshToken),
207 | ConfigurationManager.AppSettings["CallbackUrl"]
208 | );
209 |
210 | }
211 |
212 | ///
213 | /// Process the Api call
214 | ///
215 | ///
216 | ///
217 | ///
218 | private static async Task VSTSRequest(Uri uri)
219 | {
220 | string json;
221 | using (HttpClient client = new HttpClient())
222 | {
223 | json = await client.GetStringAsync(uri).ConfigureAwait(false);
224 | }
225 |
226 | try
227 | {
228 | var result = JsonConvert.DeserializeObject(json);
229 | return result;
230 | }
231 | catch (JsonException ex)
232 | {
233 | throw new ArgumentException("Unable to deserialize the VSTS response.", ex);
234 | }
235 | }
236 |
237 | ///
238 | /// Process the Api call
239 | ///
240 | ///
241 | ///
242 | ///
243 | private static async Task VSTSRequestAPI(Uri uri, string accessToken)
244 | {
245 | string json = string.Empty;
246 | using (HttpClient client = new HttpClient())
247 | {
248 | client.DefaultRequestHeaders.Add("authorization", "bearer " + accessToken);
249 | json = await client.GetStringAsync(uri).ConfigureAwait(false);
250 | }
251 |
252 | return json;
253 | }
254 |
255 | ///
256 | /// Create Uri
257 | ///
258 | ///
259 | ///
260 | ///
261 | private static Uri GetUri(string endPoint, params Tuple[] queryParams)
262 | {
263 | var queryString = HttpUtility.ParseQueryString(string.Empty);
264 | foreach (var queryparam in queryParams)
265 | {
266 | queryString[queryparam.Item1] = queryparam.Item2;
267 | }
268 |
269 | var builder = new UriBuilder(endPoint);
270 | builder.Query = queryString.ToString();
271 | return builder.Uri;
272 | }
273 | }
274 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/GetLastDialogUsedDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Threading.Tasks;
5 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
6 | {
7 | ///
8 | /// This is get Last Dialog Class. Main purpose of this class is to set the Last Active dialog information
9 | ///
10 |
11 | [Serializable]
12 | public class GetLastDialogUsedDialog : IDialog
13 | {
14 | public async Task StartAsync(IDialogContext context)
15 | {
16 | if (context == null)
17 | {
18 | throw new ArgumentNullException(nameof(context));
19 | }
20 |
21 | string dialogName = string.Empty;
22 |
23 | if (context.UserData.TryGetValue(Strings.LastDialogKey, out dialogName))
24 | {
25 | await context.PostAsync(Strings.LastDialogPromptMsg + dialogName);
26 | }
27 | else
28 | {
29 | //Set the Last Dialog in Conversation Data
30 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFetchDiaog);
31 |
32 | await context.PostAsync(Strings.LastDialogErrorMsg);
33 | }
34 |
35 | //Set the Last Dialog in Conversation Data
36 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFetchDiaog);
37 |
38 | context.Done(null);
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/HelloDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Threading.Tasks;
5 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
6 | {
7 | ///
8 | /// This is Begin Dialog Class. Main purpose of this class is to notify users that Child dialog has been called
9 | /// and its a Basic example to call Child dialog from Root Dialog.
10 | ///
11 |
12 | [Serializable]
13 | public class HelloDialog : IDialog
14 | {
15 | public async Task StartAsync(IDialogContext context)
16 | {
17 | if (context == null)
18 | {
19 | throw new ArgumentNullException(nameof(context));
20 | }
21 |
22 | //Set the Last Dialog in Conversation Data
23 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogHelloDialog);
24 |
25 | await context.PostAsync(Strings.HelloDialogMsg);
26 |
27 | context.Done(null);
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/HeroCardDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Hero Card Dialog Class. Main purpose of this class is to display the Hero Card example
12 | ///
13 |
14 | [Serializable]
15 | public class HeroCardDialog : IDialog
16 | {
17 | public async Task StartAsync(IDialogContext context)
18 | {
19 | if (context == null)
20 | {
21 | throw new ArgumentNullException(nameof(context));
22 | }
23 |
24 | //Set the Last Dialog in Conversation Data
25 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogHeroCard);
26 |
27 | var message = context.MakeMessage();
28 | var attachment = GetHeroCard();
29 |
30 | message.Attachments.Add(attachment);
31 |
32 | await context.PostAsync(message);
33 |
34 | context.Done(null);
35 | }
36 |
37 | private static Attachment GetHeroCard()
38 | {
39 | var heroCard = new HeroCard
40 | {
41 | Title = Strings.HeroCardTitle,
42 | Subtitle = Strings.HeroCardSubTitle,
43 | Text = Strings.HeroCardTextMsg,
44 | Images = new List { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
45 | Buttons = new List
46 | {
47 | new CardAction(ActionTypes.OpenUrl, Strings.HeroCardButtonCaption, value: "https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-add-rich-card-attachments"),
48 | new CardAction(ActionTypes.MessageBack, Strings.MessageBackCardButtonCaption, value: "{\"" + Strings.cmdValueMessageBack + "\": \"" + Strings.cmdValueMessageBack+ "\"}", text:Strings.cmdValueMessageBack, displayText:Strings.MessageBackDisplayedText)
49 | }
50 | };
51 |
52 | return heroCard.ToAttachment();
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/MessagebackDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Threading.Tasks;
5 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
6 | {
7 | ///
8 | /// This is Message Back Dialog Class. Main purpose of this class is to show example of Message Back event
9 | ///
10 |
11 | [Serializable]
12 | public class MessagebackDialog : IDialog
13 | {
14 | public async Task StartAsync(IDialogContext context)
15 | {
16 | if (context == null)
17 | {
18 | throw new ArgumentNullException(nameof(context));
19 | }
20 |
21 | //Set the Last Dialog in Conversation Data
22 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogMessageBackDialog);
23 |
24 | await context.PostAsync(Strings.MessageBackTitleMsg);
25 |
26 | context.Done(null);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/MultiDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Configuration;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | [Serializable]
12 | public class MultiDialog1 : IDialog
13 | {
14 | public async Task StartAsync(IDialogContext context)
15 | {
16 | if (context == null)
17 | {
18 | throw new ArgumentNullException(nameof(context));
19 | }
20 |
21 | //Set the Last Dialog in Conversation Data
22 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogMultiDialog1);
23 |
24 | await context.PostAsync(Strings.HelpCaptionMultiDialog1);
25 | context.Done(null);
26 | }
27 | }
28 |
29 | [Serializable]
30 | public class MultiDialog2 : IDialog
31 | {
32 | public async Task StartAsync(IDialogContext context)
33 | {
34 | if (context == null)
35 | {
36 | throw new ArgumentNullException(nameof(context));
37 | }
38 |
39 | var message = CreateMultiDialog(context);
40 |
41 | //Set the Last Dialog in Conversation Data
42 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogMultiDialog2);
43 |
44 | await context.PostAsync(message);
45 | context.Done(null);
46 | }
47 |
48 | private IMessageActivity CreateMultiDialog(IDialogContext context)
49 | {
50 | var message = context.MakeMessage();
51 | var attachment = CreateMultiDialogCard();
52 | message.Attachments.Add(attachment);
53 | return message;
54 | }
55 |
56 | private Attachment CreateMultiDialogCard()
57 | {
58 | return new HeroCard
59 | {
60 | Title = Strings.MultiDialogCardTitle,
61 | Subtitle = Strings.MultiDialogCardSubTitle,
62 | Text = Strings.MultiDialogCardText,
63 | Images = new List { new CardImage(ConfigurationManager.AppSettings["BaseUri"].ToString() + "/public/assets/computer_person.jpg") },
64 | Buttons = new List
65 | {
66 | new CardAction("invoke", Strings.CaptionInvokeHelloDailog, value: "{\"" + Strings.InvokeRequestJsonKey + "\": \"" + Strings.cmdHelloDialog + "\"}"),
67 | new CardAction("invoke", Strings.CaptionInvokeMultiDailog, value: "{\"" + Strings.InvokeRequestJsonKey+ "\": \"" + Strings.cmdMultiDialog1 + "\"}"),
68 | }
69 | }.ToAttachment();
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/O365ConnectorCardDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Bot.Connector.Teams.Models;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | ///
12 | /// This is Connector Card Dialog Class. Main purpose of this class is to display the Connector Card basic examples
13 | ///
14 |
15 | [Serializable]
16 | public class O365ConnectorCardDialog : IDialog
17 | {
18 | public async Task StartAsync(IDialogContext context)
19 | {
20 | if (context == null)
21 | {
22 | throw new ArgumentNullException(nameof(context));
23 | }
24 |
25 | //Set the Last Dialog in Conversation Data
26 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogConnectorCardDialog);
27 |
28 | // get the input number for the example to show if the user passed it into the command - e.g. 'show connector card 2'
29 | var activity = (IMessageActivity)context.Activity;
30 |
31 | string inputNumber = activity.Text.Substring(activity.Text.Length - 1, 1).Trim();
32 | Attachment attachment = null;
33 |
34 | /*
35 | * Below are a few more examples of more complex connector cards
36 | * To use: simply call 'connector card 2' or 'connector card 3'
37 | * Note: these examples are just filled with demo data and that demo data is NOT using the localization system
38 | * Note: these examples are leveraging an actual JSON string as their input content - more examples can be found at
39 | * https://messagecardplayground.azurewebsites.net/ - it is recommended that the developer use the method
40 | * shown above in order to get the benefits of type checking from the O365ConnectorCard class
41 | */
42 |
43 | switch (inputNumber)
44 | {
45 | case "3":
46 | attachment = O365ConnectorCardImageInSection();
47 | break;
48 | case "2":
49 | attachment = O365ConnectorCardFactsInSection();
50 | break;
51 | default:
52 | case "1":
53 | attachment = O365ConnectorCardDefault();
54 | break;
55 | }
56 |
57 | var message = context.MakeMessage();
58 | message.Attachments.Add(attachment);
59 | await context.PostAsync(message);
60 |
61 | context.Done(null);
62 | }
63 |
64 | ///
65 | /// Connector card with text in section with card title sample
66 | ///
67 | ///
68 | public static Attachment O365ConnectorCardDefault()
69 | {
70 | var o365connector = new O365ConnectorCard
71 | {
72 | Title = Strings.O365V1Title,
73 | Sections = new List
74 | {
75 | new O365ConnectorCardSection{ Text= Strings.O365V1Section1 },
76 | new O365ConnectorCardSection{ Text= Strings.O365V1Section2 }
77 | },
78 | };
79 |
80 | return o365connector.ToAttachment();
81 | }
82 |
83 | ///
84 | /// connector card with title, actvity title, facts in section sample
85 | ///
86 | ///
87 | public static Attachment O365ConnectorCardFactsInSection()
88 | {
89 | var section = new O365ConnectorCardSection
90 | {
91 | Title = Strings.O365V2Title,
92 | ActivityTitle = Strings.O365V2ActivityTitle,
93 | Facts = new List
94 | {
95 | new O365ConnectorCardFact(Strings.O365V2Fact1Key,Strings.O365V2Fact1Value),
96 | new O365ConnectorCardFact(Strings.O365V2Fact2Key,Strings.O365V2Fact2Value),
97 | new O365ConnectorCardFact(Strings.O365V2Fact3Key,Strings.O365V2Fact3Value),
98 | new O365ConnectorCardFact(Strings.O365V2Fact4Key,Strings.O365V2Fact4Value)
99 | }
100 | };
101 |
102 | var o365connector = new O365ConnectorCard
103 | {
104 | ThemeColor = Strings.O365V2themecolor,
105 | Sections = new List { section },
106 | };
107 |
108 | return o365connector.ToAttachment();
109 | }
110 |
111 | ///
112 | /// connector card with title, actvity title, activity subtitle, activity image, facts in section sample
113 | ///
114 | ///
115 | public static Attachment O365ConnectorCardImageInSection()
116 | {
117 | var section = new O365ConnectorCardSection
118 | {
119 | ActivityTitle = Strings.O365V3ActivityTitle,
120 | ActivitySubtitle = Strings.O365V3ActivitySubtitle,
121 | ActivityImage = Strings.O365V3ImageUrl,
122 | Facts = new List
123 | {
124 | new O365ConnectorCardFact(Strings.O365V3Fact1Key,Strings.O365V3Fact1Value),
125 | new O365ConnectorCardFact(Strings.O365V3Fact2Key,Strings.O365V3Fact2Value),
126 | }
127 | };
128 |
129 | var o365connector = new O365ConnectorCard
130 | {
131 | ThemeColor = Strings.O365V3ThemeColor,
132 | Summary = Strings.O365V3Summary,
133 | Title = Strings.O365V3Title,
134 | Sections = new List { section },
135 | Text = Strings.O365V3Text
136 | };
137 |
138 | return o365connector.ToAttachment();
139 | }
140 | }
141 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/PopupSigninCardDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Configuration;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | ///
12 | /// This is PopUp SignIn Dialog Class. Main purpose of this class is to Display the PopUp SignIn Card
13 | ///
14 |
15 | [Serializable]
16 | public class PopupSigninCardDialog : IDialog
17 | {
18 | public async Task StartAsync(IDialogContext context)
19 | {
20 | if (context == null)
21 | {
22 | throw new ArgumentNullException(nameof(context));
23 | }
24 |
25 | //Set the Last Dialog in Conversation Data
26 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogPopUpSignIn);
27 |
28 | var message = context.MakeMessage();
29 | var attachment = GetPopUpSignInCard();
30 |
31 | message.Attachments.Add(attachment);
32 |
33 | await context.PostAsync(message);
34 |
35 | context.Done(null);
36 | }
37 |
38 | private static Attachment GetPopUpSignInCard()
39 | {
40 | string baseUri = Convert.ToString(ConfigurationManager.AppSettings["BaseUri"]);
41 |
42 | var heroCard = new HeroCard
43 | {
44 | Title = Strings.PopUpSignInCardTitle,
45 | Buttons = new List
46 | {
47 | new CardAction(ActionTypes.Signin, Strings.PopUpSignInCardButtonTitle, value: baseUri + "/popUpSignin.html?height=200&width=200"),
48 | }
49 | };
50 |
51 | return heroCard.ToAttachment();
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/basic/ThumbnailcardDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Thumbnail Card Dialog Class. Main purpose of this class is to display the Thumbnail Card example
12 | ///
13 |
14 | [Serializable]
15 | public class ThumbnailcardDialog : IDialog
16 | {
17 | public async Task StartAsync(IDialogContext context)
18 | {
19 | if (context == null)
20 | {
21 | throw new ArgumentNullException(nameof(context));
22 | }
23 |
24 | //Set the Last Dialog in Conversation Data
25 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogThumbnailCard);
26 |
27 | var message = context.MakeMessage();
28 | var attachment = GetThumbnailCard();
29 |
30 | message.Attachments.Add(attachment);
31 |
32 | await context.PostAsync(message);
33 |
34 | context.Done(null);
35 | }
36 |
37 | private static Attachment GetThumbnailCard()
38 | {
39 | var thumbnailCard = new ThumbnailCard
40 | {
41 | Title = Strings.ThumbnailCardTitle,
42 | Subtitle = Strings.ThumbnailCardSubTitle,
43 | Text = Strings.ThumbnailCardTextMsg,
44 | Images = new List { new CardImage(Strings.ThumbnailCardImageUrl) },
45 | Buttons = new List
46 | {
47 | new CardAction(ActionTypes.OpenUrl, Strings.ThumbnailCardButtonCaption, value: "https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-add-rich-card-attachments"),
48 | new CardAction(ActionTypes.MessageBack, Strings.MessageBackCardButtonCaption, value: "{\"" + Strings.cmdValueMessageBack + "\": \"" + Strings.cmdValueMessageBack+ "\"}", text:Strings.cmdValueMessageBack, displayText:Strings.MessageBackDisplayedText)
49 | }
50 | };
51 |
52 | return thumbnailCard.ToAttachment();
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/BeginDialogExampleDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Threading.Tasks;
5 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
6 | {
7 | ///
8 | /// This is Begin Dialog Class. Main purpose of this class is to notify users that Child dialog has been called
9 | /// and its a Basic example to call Child dialog from Root Dialog.
10 | ///
11 |
12 | [Serializable]
13 | public class BeginDialogExampleDialog : IDialog
14 | {
15 | public async Task StartAsync(IDialogContext context)
16 | {
17 | if (context == null)
18 | {
19 | throw new ArgumentNullException(nameof(context));
20 | }
21 |
22 | //Set the Last Dialog in Conversation Data
23 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogBeginDialog);
24 | await context.PostAsync(Strings.BeginDialog);
25 |
26 | context.Call(new HelloDialog(), ResumeAfterHelloDialog);
27 | }
28 |
29 | private async Task ResumeAfterHelloDialog(IDialogContext context, IAwaitable result)
30 | {
31 | await context.PostAsync(Strings.BeginDialogEnd);
32 | context.Done(null);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/ListNamesDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | ///
12 | /// This is Fetch Roster Dialog Class. Main purpose of this dialog class is to Call the Roster Api and Post the
13 | /// members information (Name and Id) in Teams. This Dialog is using Thumbnail Card to show the member information in teams.
14 | ///
15 | [Serializable]
16 | public class ListNamesDialog : IDialog
17 | {
18 | public async Task StartAsync(IDialogContext context)
19 | {
20 | if (context == null)
21 | {
22 | throw new ArgumentNullException(nameof(context));
23 | }
24 |
25 | await context.PostAsync(Strings.RosterWelcomeMsgTitle);
26 | var connectorClient = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
27 | var response = await connectorClient.Conversations.GetConversationMembersAsync(context.Activity.Conversation.Id);
28 | var message = context.MakeMessage();
29 |
30 | foreach (var obj in response.ToList())
31 | {
32 | message.Attachments.Add(GetUserInformationCard(obj.Name, Convert.ToString(obj.Properties["objectId"])));
33 | }
34 |
35 | //Set the Last Dialog in Conversation Data
36 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFetchRosterDialog);
37 |
38 | await context.PostAsync(message);
39 |
40 | context.Done(null);
41 | }
42 |
43 | ///
44 | /// Create Card Template with Channel member information
45 | ///
46 | ///
47 | ///
48 | ///
49 | private static Attachment GetUserInformationCard(string userName, string objectId)
50 | {
51 | string chatUrl = "https://teams.microsoft.com/l/chat/0/0?users=8:orgid:" + objectId;
52 | var heroCard = new ThumbnailCard
53 | {
54 | Title = userName,
55 | Buttons = new List { new CardAction(ActionTypes.OpenUrl, Strings.CaptionChatButton, value: chatUrl) }
56 | };
57 |
58 | return heroCard.ToAttachment();
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/PromptDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Game Dialog Class. Here are the steps to play the games -
12 | /// 1. Its gives 3 options to users to choose.
13 | /// 2. If user choose any of the option, Bot take confirmation from the user about the choice.
14 | /// 3. Bot reply to the user based on user choice.
15 | ///
16 | [Serializable]
17 | public class PromptDialogExample : IDialog
18 | {
19 | private IEnumerable options = null;
20 | private IEnumerable choiceOptions = null;
21 |
22 | ///
23 | /// In below class constructor, we are initializing the strings Enumerable at runtime.
24 | ///
25 | public PromptDialogExample()
26 | {
27 | options = new string[] { Strings.PlayGameChoice1, Strings.PlayGameChoice2, Strings.PlayGameWrongChoice };
28 | choiceOptions = new string[] { Strings.OptionYes, Strings.OptionNo };
29 | }
30 |
31 | ///
32 | /// This is start of the Dialog and Prompting for User name
33 | ///
34 | ///
35 | ///
36 | public async Task StartAsync(IDialogContext context)
37 | {
38 | if (context == null)
39 | {
40 | throw new ArgumentNullException(nameof(context));
41 | }
42 |
43 | //Set the Last Dialog in Conversation Data
44 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogGameDialog);
45 |
46 | // This will Prompt for Name of the user.
47 | await context.PostAsync(Strings.PlayGamePromptForName);
48 | context.Wait(this.MessageReceivedAsync);
49 | }
50 |
51 | ///
52 | /// Prompt the welcome message.
53 | /// Few options for user to choose any.
54 | ///
55 | ///
56 | ///
57 | ///
58 | private async Task MessageReceivedAsync(IDialogContext context, IAwaitable result)
59 | {
60 | if (result == null)
61 | {
62 | throw new InvalidOperationException((nameof(result)) + Strings.NullException);
63 | }
64 |
65 | //Prompt the user with welcome message before game starts
66 | var resultActivity = await result;
67 | await context.PostAsync(Strings.PlayGameAnswerForName + resultActivity.Text);
68 |
69 | //Here we are prompting few options for user to choose any.
70 | PromptDialog.Choice(
71 | context,
72 | this.ChooseOptions,
73 | options,
74 | Strings.PlayGameStartMsg,
75 | Strings.PromptInvalidMsg,
76 | 3);
77 | }
78 |
79 | ///
80 | /// In this methos, we are taking confirmation from user about the selection.
81 | ///
82 | ///
83 | ///
84 | ///
85 | private async Task ChooseOptions(IDialogContext context, IAwaitable result)
86 | {
87 | var selctedChoice = await result;
88 |
89 | //Once User choose any of the given option, we are taking confirmation from user about the selection.
90 | PromptDialog.Choice(
91 | context,
92 | this.ResultedOptions,
93 | choiceOptions,
94 | Strings.PlayGameReplyMsg + "'" + selctedChoice + "'?",
95 | Strings.PromptInvalidMsg,
96 | 3);
97 | }
98 |
99 | ///
100 | /// End this dialog and pass the user selection to ResumeAfterFlowGame method in Root Dialog
101 | ///
102 | ///
103 | ///
104 | ///
105 | private async Task ResultedOptions(IDialogContext context, IAwaitable result)
106 | {
107 | if (result == null)
108 | {
109 | throw new InvalidOperationException((nameof(result)) + Strings.NullException);
110 | }
111 |
112 | var selctedChoice = await result;
113 | if (selctedChoice == Strings.OptionYes)
114 | {
115 | context.Done(true);
116 | }
117 | else
118 | {
119 | context.Done(false);
120 | }
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/Quiz1Dialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Quiz1 Dialog and Child Dialog of Quiz Dialog.
12 | /// Calling Sequence of this Dialog is :-
13 | /// Root Dialog --> Quiz Dialog
14 | /// Quiz Dialog --> Quiz1 Dialog (Child dialog of Quiz Dialog)
15 | /// Once this dialog Ends, it will resume in Quiz Dialog
16 | ///
17 | [Serializable]
18 | public class Quiz1Dialog : IDialog
19 | {
20 | public async Task StartAsync(IDialogContext context)
21 | {
22 | if (context == null)
23 | {
24 | throw new ArgumentNullException(nameof(context));
25 | }
26 |
27 | var message = CreateQuiz(context);
28 |
29 | //Set the Last Dialog in Conversation Data
30 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogQuiz1Dialog);
31 |
32 | await context.PostAsync(message);
33 | context.Wait(this.MessageReceivedAsync);
34 | }
35 |
36 | #region Create Quiz Message Card
37 | private IMessageActivity CreateQuiz(IDialogContext context)
38 | {
39 | var message = context.MakeMessage();
40 | var attachment = CreateQuizCard();
41 | message.Attachments.Add(attachment);
42 | return message;
43 | }
44 |
45 | private Attachment CreateQuizCard()
46 | {
47 | return new HeroCard
48 | {
49 | Title = Strings.Quiz1Question,
50 | Images = new List { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
51 | Buttons = new List
52 | {
53 | new CardAction(ActionTypes.ImBack, Strings.OptionYes, value: Strings.OptionYes),
54 | new CardAction(ActionTypes.ImBack, Strings.OptionNo, value: Strings.OptionNo)
55 | }
56 | }.ToAttachment();
57 | }
58 | #endregion
59 |
60 | private async Task MessageReceivedAsync(IDialogContext context, IAwaitable result)
61 | {
62 | if (result == null)
63 | {
64 | throw new InvalidOperationException((nameof(result)) + Strings.NullException);
65 | }
66 |
67 | var activity = await result;
68 |
69 | if (activity.Text.ToLower() == Strings.OptionYes)
70 | {
71 | await context.PostAsync(Strings.QuizAnswerYes);
72 | context.Done(null);
73 | }
74 | else if (activity.Text.ToLower() == Strings.OptionNo)
75 | {
76 | await context.PostAsync(Strings.QuizAnswerNo);
77 | context.Done(null);
78 | }
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/Quiz2Dialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Quiz2 Dialog and Child of Quiz Dialog as well.
12 | /// Calling sequence for this dialog is :-
13 | /// Quiz Dialog - > Quiz1 Dialog.
14 | /// Quiz1 Dialog Ends -> Quiz2 Dialog (Child dialog of Quiz Dialog).
15 | /// Once this dialog Ends, it will resume in Quiz Dialog.
16 | ///
17 | [Serializable]
18 | public class Quiz2Dialog : IDialog
19 | {
20 | public async Task StartAsync(IDialogContext context)
21 | {
22 | if (context == null)
23 | {
24 | throw new ArgumentNullException(nameof(context));
25 | }
26 |
27 | var message = CreateQuiz(context);
28 |
29 | //Set the Last Dialog in Conversation Data
30 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogQuiz2Dialog);
31 |
32 | await context.PostAsync(message);
33 |
34 | context.Wait(this.MessageReceivedAsync);
35 | }
36 |
37 | #region Create Quiz Message Card
38 | private Attachment CreateQuizCard()
39 | {
40 | return new HeroCard
41 | {
42 | Title = Strings.Quiz2Question,
43 | Images = new List { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
44 | Buttons = new List
45 | {
46 | new CardAction(ActionTypes.ImBack, Strings.OptionYes, value: Strings.OptionYes),
47 | new CardAction(ActionTypes.ImBack, Strings.OptionNo, value: Strings.OptionNo)
48 | }
49 | }.ToAttachment();
50 | }
51 |
52 | private IMessageActivity CreateQuiz(IDialogContext context)
53 | {
54 | var message = context.MakeMessage();
55 | var attachment = CreateQuizCard();
56 | message.Attachments.Add(attachment);
57 | return message;
58 | }
59 | #endregion
60 |
61 | private async Task MessageReceivedAsync(IDialogContext context, IAwaitable result)
62 | {
63 | if (result == null)
64 | {
65 | throw new InvalidOperationException((nameof(result)) + Strings.NullException);
66 | }
67 |
68 | var activity = await result as Activity;
69 |
70 | if (activity.Text.ToLower() == Strings.OptionYes)
71 | {
72 | await context.PostAsync(Strings.QuizAnswerYes);
73 | context.Done(null);
74 | }
75 | else if (activity.Text.ToLower() == Strings.OptionNo)
76 | {
77 | await context.PostAsync(Strings.QuizAnswerNo);
78 | context.Done(null);
79 | }
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/moderate/QuizFullDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
7 | {
8 | ///
9 | /// This is Quiz Dialog class and its a example for below scenarios
10 | /// 1. Call Main Dialog from Root Dialog ( Root Dialog -> Quiz Dialog)
11 | /// 2. Call Dialog Within Dialog ( Quiz Dialog -> Quiz1 Dialog)
12 | /// 3. Call Another Dialog after end of Child Dialog ( Quiz1 Dialog --> Quiz2 Dialog, Quiz2 only be called when Quiz1 Completed, its not child dialog of Quiz1 Dialog)
13 | /// 4. Once Quiz 2 is Done -> it will Resume Quiz Dialog
14 | /// 5. Once Quiz Dialog Ends -> it will ResumeRoot Dialog
15 | ///
16 | [Serializable]
17 | public class QuizFullDialog : IDialog
18 | {
19 | public async Task StartAsync(IDialogContext context)
20 | {
21 | if (context == null)
22 | {
23 | throw new ArgumentNullException(nameof(context));
24 | }
25 |
26 | //Set the Last Dialog in Conversation Data
27 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogQuizDialog);
28 |
29 | await context.PostAsync(Strings.QuizDialogBeginTitle);
30 | context.Call(new Quiz1Dialog(), ResumeAfterRunQuiz1Dialog);
31 | }
32 |
33 | private async Task ResumeAfterRunQuiz1Dialog(IDialogContext context, IAwaitable result)
34 | {
35 | await context.PostAsync(Strings.Quiz1ThanksTitleMsg);
36 | context.Call(new Quiz2Dialog(), this.ResumeAfterBeginQuiz2);
37 | }
38 |
39 | private async Task ResumeAfterBeginQuiz2(IDialogContext context, IAwaitable result)
40 | {
41 | await context.PostAsync(Strings.QuizThanksTitleMsg);
42 | context.Done(null);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/AtMentionDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Bot.Connector.Teams;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Threading.Tasks;
7 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
8 | {
9 | ///
10 | /// This is At Mention Dialog Class. Main purpose of this dialog class is to Atmention (@mention)
11 | /// the user who has started the conversation.
12 | /// we can pass ChannelAccount object as first parameter of AddMentionToText method to @mention any user.
13 | /// e.g. ChannelAccount userInformation = new ChannelAccount("29:1TPHVQrnqOI3_FZbeY32VvlBwo1trPhN96SiKYP3av-QCKYGlLBApj-w9fgoI9SCUz4bEmzo9tVlSQdHzgoSzeQ", "Ashish");
14 | ///
15 |
16 | [Serializable]
17 | public class AtMentionDialog : IDialog
18 | {
19 | public async Task StartAsync(IDialogContext context)
20 | {
21 | if (context == null)
22 | {
23 | throw new ArgumentNullException(nameof(context));
24 | }
25 |
26 | var message = context.MakeMessage();
27 | Activity replyActivity = message as Activity;
28 | replyActivity.AddMentionToText(context.Activity.From, MentionTextLocation.PrependText);
29 | await context.PostAsync(replyActivity);
30 |
31 | //Set the Last Dialog in Conversation Data
32 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogAtMentionDialog);
33 | context.Done(null);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/DeepLinkStaticTabDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Configuration;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | ///
12 | /// This is DeepLink Dialog Class. Main purpose of this class is to show Deep link from Bot to Tab example
13 | ///
14 |
15 | [Serializable]
16 | public class DeepLinkStaticTabDialog : IDialog
17 | {
18 | private const string TabEntityID = "statictab";
19 | private const string TabConfigEntityID = "configTab";
20 | private string BotId { get; set; }
21 | private bool IsChannelUser { get; set; } = false;
22 | private string ChannelId { get; set; }
23 | private string TabUrl { get; set; }
24 | private string ButtonCaption { get; set; }
25 | private string DeepLinkCardTitle { get; set; }
26 |
27 | public async Task StartAsync(IDialogContext context)
28 | {
29 | if (context == null)
30 | {
31 | throw new ArgumentNullException(nameof(context));
32 | }
33 |
34 | BotId = ConfigurationManager.AppSettings["MicrosoftAppId"];
35 |
36 | GetChannelID(context);
37 |
38 | var message = CreateDeepLinkMessage(context);
39 |
40 | //Set the Last Dialog in Conversation Data
41 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogDeepLinkStaticTabDialog);
42 |
43 | await context.PostAsync(message);
44 |
45 | context.Done(null);
46 | }
47 |
48 | #region Create Deep Link Tab Card
49 | private IMessageActivity CreateDeepLinkMessage(IDialogContext context)
50 | {
51 | var message = context.MakeMessage();
52 | var attachment = CreateDeepLinkCard();
53 | message.Attachments.Add(attachment);
54 | return message;
55 | }
56 |
57 | private Attachment CreateDeepLinkCard()
58 | {
59 | if (IsChannelUser)
60 | {
61 | TabUrl = GetConfigTabDeepLinkURL(ChannelId);
62 | ButtonCaption = Strings.DeepLinkCardConfigButtonCaption;
63 | DeepLinkCardTitle = Strings.DeepLinkCardConfigTitle;
64 | }
65 | else
66 | {
67 | TabUrl = GetStaticTabDeepLinkURL();
68 | ButtonCaption = Strings.DeepLinkCard1To1ButtonCaption;
69 | DeepLinkCardTitle = Strings.DeepLinkCard1To1Title;
70 | }
71 |
72 | return new HeroCard
73 | {
74 | Title = DeepLinkCardTitle,
75 | Buttons = new List
76 | {
77 | new CardAction(ActionTypes.OpenUrl, ButtonCaption, value: TabUrl),
78 | }
79 | }.ToAttachment();
80 | }
81 |
82 | private string GetStaticTabDeepLinkURL()
83 | {
84 | //Example - BaseURL + 28:BotId + TabEntityId (set in the manifest) + ?conversationType=chat
85 | return "https://teams.microsoft.com/l/entity/28:" + BotId + "/" + TabEntityID + "?conversationType=chat";
86 | }
87 |
88 | private string GetConfigTabDeepLinkURL(string channelId)
89 | {
90 | //Example - BaseURL + BotId + TabConfigEntityId (e.g. entityId: "configTab" : it should be same which we have set at the time of Tab Creation like below) + ?context= + {"channelId":"19:47051e5643ed49b58665e1250b6db460@thread.skype"} (should be encoded)
91 | //microsoftTeams.settings.setSettings({ suggestedDisplayName: "Bot Info", contentUrl: createTabUrl(), entityId: "configTab" });
92 |
93 | channelId = channelId.Replace("19:", "19%3a")
94 | .Replace("@thread.skype", "%40thread.skype");
95 |
96 | return "https://teams.microsoft.com/l/entity/" + BotId + "/" + TabConfigEntityID + "?context=%7B%22channelId%22%3A%22" + channelId + "%22%7D";
97 | }
98 |
99 | private void GetChannelID(IDialogContext context)
100 | {
101 |
102 | IsChannelUser = false;
103 |
104 | if (context.Activity.ChannelData != null)
105 | {
106 | ChannelId = context.Activity.ChannelData["teamsChannelId"];
107 |
108 | if (!string.IsNullOrEmpty(ChannelId))
109 | {
110 | IsChannelUser = true;
111 | }
112 | else
113 | {
114 | IsChannelUser = false;
115 | }
116 | }
117 | }
118 | #endregion
119 | }
120 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/DisplayCardsDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
7 | {
8 | ///
9 | /// This is Card Dialog Class. Main purpose of this dialog class is to post different types of Cards example like Hero Card, Thumbnail Card etc.
10 | ///
11 | [Serializable]
12 | public class DisplayCardsDialog : IDialog
13 | {
14 | private IEnumerable options = null;
15 |
16 | public DisplayCardsDialog()
17 | {
18 | options = new List { Strings.DisplayCardHeroCard, Strings.DisplayCardThumbnailCard, Strings.DisplayCardO365ConnectorCardDefault, Strings.DisplayCardO365ConnectorCard2, Strings.DisplayCardO365ConnectorCard3, Strings.DisplayCardO365ConnectorActionableCardDefault, Strings.DisplayCardO365ConnectorActionableCard2, Strings.DisplayCardAdaptiveCard };
19 | }
20 |
21 | public async Task StartAsync(IDialogContext context)
22 | {
23 | if (context == null)
24 | {
25 | throw new ArgumentNullException(nameof(context));
26 | }
27 |
28 | //Set the Last Dialog in Conversation Data
29 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogDisplayCardsDialog);
30 |
31 | await context.PostAsync(Strings.DisplayCardMsgTitle);
32 |
33 | PromptDialog.Choice(
34 | context,
35 | this.DisplaySelectedCard,
36 | options,
37 | Strings.DisplayCardPromptText,
38 | Strings.PromptInvalidMsg,
39 | 3);
40 | }
41 |
42 | public async Task DisplaySelectedCard(IDialogContext context, IAwaitable result)
43 | {
44 | var selectedCard = await result;
45 |
46 | if (selectedCard.Equals(Strings.DisplayCardHeroCard))
47 | {
48 | context.Call(new HeroCardDialog(), ResumeAfterOptionDialog);
49 | }
50 | else if (selectedCard.Equals(Strings.DisplayCardThumbnailCard))
51 | {
52 | context.Call(new ThumbnailcardDialog(), ResumeAfterOptionDialog);
53 | }
54 | else if (selectedCard.Equals(Strings.DisplayCardO365ConnectorCardDefault))
55 | {
56 | context.Call(new O365ConnectorCardDialog(), ResumeAfterOptionDialog);
57 | }
58 | else if (selectedCard.Equals(Strings.DisplayCardO365ConnectorCard2))
59 | {
60 | context.Call(new O365ConnectorCardDialog(), ResumeAfterOptionDialog);
61 | }
62 | else if (selectedCard.Equals(Strings.DisplayCardO365ConnectorCard3))
63 | {
64 | context.Call(new O365ConnectorCardDialog(), ResumeAfterOptionDialog);
65 | }
66 | else if (selectedCard.Equals(Strings.DisplayCardO365ConnectorActionableCardDefault))
67 | {
68 | context.Call(new O365ConnectorCardActionsDialog(), ResumeAfterOptionDialog);
69 | }
70 | else if (selectedCard.Equals(Strings.DisplayCardO365ConnectorActionableCard2))
71 | {
72 | context.Call(new O365ConnectorCardActionsDialog(), ResumeAfterOptionDialog);
73 | }
74 | else if (selectedCard.Equals(Strings.DisplayCardAdaptiveCard))
75 | {
76 | context.Call(new AdaptiveCardDialog(), ResumeAfterOptionDialog);
77 | }
78 | }
79 |
80 | private async Task ResumeAfterOptionDialog(IDialogContext context, IAwaitable result)
81 | {
82 | try
83 | {
84 | var message = await result;
85 | context.Done(null);
86 | }
87 | catch (Exception ex)
88 | {
89 | await context.PostAsync(Strings.DisplayCardErrorMsg + ex.Message);
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/FetchRosterDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Fetch Roster Payload Dialog Class. Main purpose of this dialog class is to Call the Roster Api and Post the
12 | /// full JSON Payload in Teams returned by Roster Api.
13 | ///
14 | [Serializable]
15 | public class FetchRosterDialog : IDialog
16 | {
17 | public async Task StartAsync(IDialogContext context)
18 | {
19 | if (context == null)
20 | {
21 | throw new ArgumentNullException(nameof(context));
22 | }
23 |
24 | await context.PostAsync(Strings.RosterWelcomeMsgTitle);
25 | var connectorClient = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
26 |
27 | var response = await connectorClient.Conversations.GetConversationMembersAsync(context.Activity.Conversation.Id);
28 | string output = JsonConvert.SerializeObject(response);
29 |
30 | var message = context.MakeMessage();
31 | message.Text = output;
32 |
33 | //Set the Last Dialog in Conversation Data
34 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFetchPayloadRosterDialog);
35 |
36 | await context.PostAsync(message);
37 |
38 | context.Done(null);
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/FetchTeamsInfoDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Bot.Connector.Teams;
4 | using Microsoft.Bot.Connector.Teams.Models;
5 | using Microsoft.Teams.TemplateBotCSharp.Properties;
6 | using System;
7 | using System.Threading.Tasks;
8 | using System.Web;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
11 | {
12 | ///
13 | /// This is Fetch Teams Info Dialog Class main purpose of this dialog class is to display Team Name, TeamId and AAD GroupId.
14 | ///
15 | [Serializable]
16 | public class FetchTeamsInfoDialog : IDialog
17 | {
18 | public async Task StartAsync(IDialogContext context)
19 | {
20 | if (context == null)
21 | {
22 | throw new ArgumentNullException(nameof(context));
23 | }
24 |
25 | var team = context.Activity.GetChannelData().Team;
26 |
27 | if (team != null)
28 | {
29 | var connectorClient = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
30 |
31 | // Handle for channel conversation, AAD GroupId only exists within channel
32 | TeamDetails teamDetails = await connectorClient.GetTeamsConnectorClient().Teams.FetchTeamDetailsAsync(team.Id);
33 |
34 | var message = context.MakeMessage();
35 | message.Text = GenerateTable(teamDetails);
36 |
37 | await context.PostAsync(message);
38 | }
39 | else
40 | {
41 | // Handle for 1 to 1 bot conversation
42 | await context.PostAsync(Strings.TeamInfo1To1ConversationError);
43 | }
44 |
45 | //Set the Last Dialog in Conversation Data
46 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogFetchTeamInfoDialog);
47 |
48 | context.Done(null);
49 | }
50 |
51 | ///
52 | /// Generate HTML dynamically to show TeamId, TeamName and AAD GroupId in table format
53 | ///
54 | ///
55 | ///
56 | private string GenerateTable(TeamDetails teamDetails)
57 | {
58 | if (teamDetails == null)
59 | {
60 | return string.Empty;
61 | }
62 |
63 | string tableHtml = $@"
64 | Team id {HttpUtility.HtmlEncode(teamDetails.Id)}
65 | Team name {HttpUtility.HtmlEncode(teamDetails.Name)}
66 | AAD group id {HttpUtility.HtmlEncode(teamDetails.AadGroupId)}
67 |
";
68 | return tableHtml;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/HelpDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Help Dialog Class. Main purpose of this dialog class is to post the help commands in Teams.
12 | /// These are Actionable help commands for easy to use.
13 | ///
14 | [Serializable]
15 | public class HelpDialog : IDialog
16 | {
17 | public async Task StartAsync(IDialogContext context)
18 | {
19 | if (context == null)
20 | {
21 | throw new ArgumentNullException(nameof(context));
22 | }
23 |
24 | var message = context.MakeMessage();
25 |
26 | //Set the Last Dialog in Conversation Data
27 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogHelpDialog);
28 |
29 | // This will create Interactive Card with help command buttons
30 |
31 | message.Attachments = new List
32 | {
33 | new HeroCard(Strings.HelpTitle)
34 | {
35 | Buttons = new List
36 | {
37 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionRunQuiz, value: Strings.cmdRunQuiz),
38 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionFetchRoster, value: Strings.cmdFetchRoster),
39 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionPlayGame, value: Strings.cmdPrompt),
40 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionRosterPayload, value: Strings.cmdRosterPayload),
41 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionDialogFlow, value: Strings.cmdDialogFlow),
42 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionHelloDialog, value: Strings.cmdHelloDialog),
43 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionAtMention, value: Strings.cmdRunAtMentionDialog),
44 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionMultiDialog1, value: Strings.cmdMultiDialog1),
45 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionMultiDialog2, value: Strings.cmdMultiDialog2),
46 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionFetchLastDialog, value: Strings.cmdFetchLastDialog),
47 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionSetupMessage, value: Strings.cmdSetupMessage),
48 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionUpdateMessage, value: Strings.cmdUpdateMessage),
49 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionSend1on1Conversation, value: Strings.cmdSend1on1ConversationDialog),
50 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionUpdateCard, value: Strings.cmdUpdateCard),
51 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionDisplayCards, value: Strings.cmdDisplayCards),
52 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionDeepLink, value: Strings.cmdDeepLink),
53 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionAuthSample, value: Strings.cmdAuthSampleDialog),
54 | new CardAction(ActionTypes.ImBack, Strings.HelpLocalTimeZone, value: Strings.cmdLocalTime),
55 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionMessageBack, value: Strings.cmdMessageBack),
56 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionPopUpSignIn, value: Strings.cmdPopUpSignIn),
57 | new CardAction(ActionTypes.ImBack, Strings.HelpCaptionTeamInfo, value: Strings.cmdGetTeamInfo)
58 | }
59 | }.ToAttachment()
60 | };
61 |
62 | await context.PostAsync(message);
63 | context.Done(null);
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/ProactiveMsgTo1to1Dialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Bot.Connector.Teams.Models;
4 | using Microsoft.Teams.TemplateBotCSharp.Properties;
5 | using System;
6 | using System.Threading.Tasks;
7 |
8 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
9 | {
10 | ///
11 | /// This is Proactive Message Dialog Class. Main purpose of this class is to show the Send Proactive Message Example
12 | ///
13 | [Serializable]
14 | public class ProactiveMsgTo1to1Dialog : IDialog
15 | {
16 | public async Task StartAsync(IDialogContext context)
17 | {
18 | if (context == null)
19 | {
20 | throw new ArgumentNullException(nameof(context));
21 | }
22 |
23 | //Set the Last Dialog in Conversation Data
24 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogSend1on1Dialog);
25 |
26 | var userId = context.Activity.From.Id;
27 | var botId = context.Activity.Recipient.Id;
28 | var botName = context.Activity.Recipient.Name;
29 |
30 | var channelData = context.Activity.GetChannelData();
31 | var connectorClient = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
32 |
33 | var parameters = new ConversationParameters
34 | {
35 | Bot = new ChannelAccount(botId, botName),
36 | Members = new ChannelAccount[] { new ChannelAccount(userId) },
37 | ChannelData = new TeamsChannelData
38 | {
39 | Tenant = channelData.Tenant
40 | }
41 | };
42 |
43 | var conversationResource = await connectorClient.Conversations.CreateConversationAsync(parameters);
44 |
45 | var message = Activity.CreateMessageActivity();
46 | message.From = new ChannelAccount(botId, botName);
47 | message.Conversation = new ConversationAccount(id: conversationResource.Id.ToString());
48 | message.Text = Strings.Send1on1Prompt;
49 |
50 | await connectorClient.Conversations.SendToConversationAsync((Activity)message);
51 |
52 | context.Done(null);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/UpdateCardMsgDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using Microsoft.Teams.TemplateBotCSharp.Utility;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Configuration;
8 | using System.Threading.Tasks;
9 |
10 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
11 | {
12 | ///
13 | /// This is update card dialog class. Main purpose of this class is to update the card, if user has already setup the card message from below dialog file
14 | /// microsoft-teams-sample-complete-csharp\template-bot-master-csharp\src\dialogs\examples\teams\updatecardmsgsetupdialog.cs
15 | ///
16 | [Serializable]
17 | public class UpdateCardMsgDialog : IDialog
18 | {
19 | public int updateCounter;
20 |
21 | public async Task StartAsync(IDialogContext context)
22 | {
23 | if (context == null)
24 | {
25 | throw new ArgumentNullException(nameof(context));
26 | }
27 |
28 | if (!string.IsNullOrEmpty(context.Activity.ReplyToId))
29 | {
30 | Activity activity = context.Activity as Activity;
31 | updateCounter = TemplateUtility.ParseUpdateCounterJson(activity);
32 |
33 | var updatedMessage = CreateUpdatedMessage(context);
34 |
35 | ConnectorClient client = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
36 |
37 | try
38 | {
39 | ResourceResponse resp = await client.Conversations.UpdateActivityAsync(context.Activity.Conversation.Id, context.Activity.ReplyToId, (Activity)updatedMessage);
40 | await context.PostAsync(Strings.UpdateCardMessageConfirmation);
41 | }
42 | catch (Exception ex)
43 | {
44 | await context.PostAsync(Strings.ErrorUpdatingCard + ex.Message);
45 | }
46 | }
47 | else
48 | {
49 | await context.PostAsync(Strings.NoMsgToUpdate);
50 | }
51 |
52 | context.Done(null);
53 |
54 | //Set the Last Dialog in Conversation Data
55 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogSetupUpdateCard);
56 | }
57 |
58 | #region Create Updated Card Message
59 | private IMessageActivity CreateUpdatedMessage(IDialogContext context)
60 | {
61 | var message = context.MakeMessage();
62 | var attachment = CreateUpdatedCardAttachment();
63 | message.Attachments.Add(attachment);
64 | return message;
65 | }
66 |
67 | private Attachment CreateUpdatedCardAttachment()
68 | {
69 | return new HeroCard
70 | {
71 | Title = Strings.UpdatedCardTitle + " " + updateCounter,
72 | Subtitle = Strings.UpdatedCardSubTitle,
73 | Images = new List { new CardImage(ConfigurationManager.AppSettings["BaseUri"].ToString() + "/public/assets/computer_person.jpg") },
74 | Buttons = new List
75 | {
76 | new CardAction(ActionTypes.MessageBack, Strings.UpdateCardButtonCaption, value: "{\"updateKey\": \"" + ++updateCounter + "\"}", text: DialogMatches.UpdateCard)
77 | }
78 | }.ToAttachment();
79 | }
80 | #endregion
81 | }
82 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/UpdateCardMsgSetupDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Configuration;
7 | using System.Threading.Tasks;
8 |
9 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
10 | {
11 | ///
12 | /// This is setup card dialog class. Main purpose of this class is to setup the card message and then user can update the card using below update dialog file
13 | /// microsoft-teams-sample-complete-csharp\template-bot-master-csharp\src\dialogs\examples\teams\UpdateCardMsgDialog.cs
14 | ///
15 | [Serializable]
16 | public class UpdateCardMsgSetupDialog : IDialog
17 | {
18 | public int updateCounter = 0;
19 | public async Task StartAsync(IDialogContext context)
20 | {
21 | if (context == null)
22 | {
23 | throw new ArgumentNullException(nameof(context));
24 | }
25 |
26 | var message = SetupMessage(context);
27 | await context.PostAsync(message);
28 |
29 | //Set the Last Dialog in Conversation Data
30 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogSetupUpdateCard);
31 |
32 | context.Done(null);
33 | }
34 |
35 | #region Create Message to Setup Card
36 | private IMessageActivity SetupMessage(IDialogContext context)
37 | {
38 | var message = context.MakeMessage();
39 | var attachment = CreateCard();
40 | message.Attachments.Add(attachment);
41 | return message;
42 | }
43 |
44 | private Attachment CreateCard()
45 | {
46 | return new HeroCard
47 | {
48 | Title = Strings.SetUpCardTitle,
49 | Subtitle = Strings.SetupCardSubTitle,
50 | Images = new List { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
51 | Buttons = new List
52 | {
53 | new CardAction(ActionTypes.MessageBack, Strings.UpdateCardButtonCaption, value: "{\"updateKey\": \"" + ++updateCounter + "\"}", text: DialogMatches.UpdateCard)
54 | }
55 | }.ToAttachment();
56 | }
57 | #endregion
58 | }
59 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/UpdateTextMsgDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
8 | {
9 | ///
10 | /// This is Update Text Dialog Class. Main purpose of this class is to Update the Text in Bot
11 | ///
12 | [Serializable]
13 | public class UpdateTextMsgDialog : IDialog
14 | {
15 | public async Task StartAsync(IDialogContext context)
16 | {
17 | if (context == null)
18 | {
19 | throw new ArgumentNullException(nameof(context));
20 | }
21 |
22 | string cachedMessage = string.Empty;
23 |
24 | if (context.UserData.TryGetValue(Strings.SetUpMsgKey, out cachedMessage))
25 | {
26 | IMessageActivity reply = context.MakeMessage();
27 | reply.Text = Strings.UpdateMessagePrompt;
28 |
29 | ConnectorClient client = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
30 | ResourceResponse resp = await client.Conversations.UpdateActivityAsync(context.Activity.Conversation.Id, cachedMessage, (Activity)reply);
31 |
32 | await context.PostAsync(Strings.UpdateMessageConfirmation);
33 | }
34 | else
35 | {
36 | await context.PostAsync(Strings.ErrorTextMessageUpdate);
37 | }
38 |
39 | //Set the Last Dialog in Conversation Data
40 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogUpdateMessasge);
41 |
42 | context.Done(null);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/src/dialogs/examples/teams/UpdateTextMsgSetupDialog.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Connector;
3 | using Microsoft.Teams.TemplateBotCSharp.Properties;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | namespace Microsoft.Teams.TemplateBotCSharp.Dialogs
8 | {
9 | ///
10 | /// This is Update Setup Text Dialog Class. Main purpose of this class is to Setup the text message that will be update later in Bot example.
11 | ///
12 | [Serializable]
13 | public class UpdateTextMsgSetupDialog : IDialog
14 | {
15 | public async Task StartAsync(IDialogContext context)
16 | {
17 | if (context == null)
18 | {
19 | throw new ArgumentNullException(nameof(context));
20 | }
21 |
22 | IMessageActivity reply = context.MakeMessage();
23 | reply.Text = Strings.SetupMessagePrompt;
24 |
25 | ConnectorClient client = new ConnectorClient(new Uri(context.Activity.ServiceUrl));
26 | ResourceResponse resp = await client.Conversations.ReplyToActivityAsync((Activity)reply);
27 |
28 | //Set the Last Dialog in Conversation Data
29 | context.UserData.SetValue(Strings.LastDialogKey, Strings.LastDialogSetupMessasge);
30 |
31 | //Set the Last Dialog in Conversation Data
32 | context.UserData.SetValue(Strings.SetUpMsgKey, resp.Id.ToString());
33 |
34 | context.Done(null);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/utility/InvokeHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Connector;
2 | using Microsoft.Teams.TemplateBotCSharp.Properties;
3 | using System;
4 |
5 | namespace Microsoft.Teams.TemplateBotCSharp.Utility
6 | {
7 | public static class InvokeHandler
8 | {
9 | ///
10 | /// Parse the invoke value and change the activity type as message
11 | ///
12 | ///
13 | ///
14 | public static IMessageActivity HandleInvokeRequest(IMessageActivity activity)
15 | {
16 | if (activity == null)
17 | {
18 | throw new ArgumentNullException(nameof(activity));
19 | }
20 |
21 | activity.Text = TemplateUtility.ParseInvokeRequestJson(activity.Value.ToString());
22 |
23 | //Change the Type of Activity to work in exisiting Root Dialog Architecture
24 | activity.Type = Strings.MessageActivity;
25 |
26 | return activity;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/template-bot-master-csharp/utility/TemplateUtility.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Bot.Builder.Dialogs;
2 | using Microsoft.Bot.Builder.Dialogs.Internals;
3 | using Microsoft.Bot.Connector;
4 | using Microsoft.Bot.Connector.Teams;
5 | using Microsoft.Bot.Connector.Teams.Models;
6 | using Microsoft.Teams.TemplateBotCSharp.Properties;
7 | using Newtonsoft.Json;
8 | using Newtonsoft.Json.Linq;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 |
14 | namespace Microsoft.Teams.TemplateBotCSharp.Utility
15 | {
16 | ///
17 | /// Get the locale from incoming activity payload and handle compose extension methods
18 | ///
19 | public static class TemplateUtility
20 | {
21 | public static string GetLocale(Activity activity)
22 | {
23 | if (activity == null)
24 | {
25 | throw new ArgumentNullException(nameof(activity));
26 | }
27 |
28 | //Get the locale from activity
29 | if (activity.Entities != null)
30 | {
31 | foreach(var entity in activity.Entities)
32 | {
33 | if (string.Equals(entity.Type.ToString().ToLower(), "clientinfo"))
34 | {
35 | var locale = entity.Properties["locale"];
36 | if (locale != null)
37 | {
38 | return locale.ToString();
39 | }
40 | }
41 | }
42 | }
43 | return activity.Locale;
44 | }
45 |
46 | public static ComposeExtensionAttachment CreateComposeExtensionCardsAttachments(WikiHelperSearchResult wikiResult, string selectedType)
47 | {
48 | return GetComposeExtensionMainResultAttachment(wikiResult, selectedType).ToComposeExtensionAttachment(GetComposeExtensionPreviewAttachment(wikiResult, selectedType));
49 | }
50 |
51 | public static ComposeExtensionAttachment CreateComposeExtensionCardsAttachmentsSelectedItem(WikiHelperSearchResult wikiResult, string selectedType)
52 | {
53 | return GetComposeExtensionMainResultAttachment(wikiResult, selectedType).ToComposeExtensionAttachment();
54 | }
55 |
56 | public static Attachment GetComposeExtensionMainResultAttachment(WikiHelperSearchResult wikiResult, string selectedType)
57 | {
58 | CardType cardType;
59 | Attachment cardAttachment = null;
60 |
61 | var images = new List
62 | {
63 | new CardImage(wikiResult.imageUrl)
64 | };
65 |
66 | if (Enum.TryParse(selectedType, out cardType))
67 | {
68 | switch (cardType)
69 | {
70 | case CardType.hero:
71 | cardAttachment = new HeroCard()
72 | {
73 | Title = wikiResult.highlightedTitle,
74 | Text = wikiResult.text,
75 | Images = images
76 | }.ToAttachment();
77 | break;
78 | case CardType.thumbnail:
79 | cardAttachment = new ThumbnailCard()
80 | {
81 | Title = wikiResult.highlightedTitle,
82 | Text = wikiResult.text,
83 | Images = images
84 | }.ToAttachment();
85 | break;
86 | }
87 | }
88 |
89 | return cardAttachment;
90 | }
91 |
92 | public static Attachment GetComposeExtensionPreviewAttachment(WikiHelperSearchResult wikiResult, string selectedType)
93 | {
94 | string invokeVal = GetCardActionInvokeValue(wikiResult);
95 | var tapAction = new CardAction("invoke", value: invokeVal);
96 |
97 | CardType cardType;
98 | Attachment cardAttachment = null;
99 |
100 | var images = new List
101 | {
102 | new CardImage(wikiResult.imageUrl)
103 | };
104 |
105 | if (Enum.TryParse(selectedType, out cardType))
106 | {
107 | switch (cardType)
108 | {
109 | case CardType.hero:
110 | cardAttachment = new HeroCard()
111 | {
112 | Title = wikiResult.highlightedTitle,
113 | Tap = tapAction,
114 | Images = images
115 | }.ToAttachment();
116 | break;
117 | case CardType.thumbnail:
118 | cardAttachment = new ThumbnailCard()
119 | {
120 | Title = wikiResult.highlightedTitle,
121 | Tap = tapAction,
122 | Images = images
123 | }.ToAttachment();
124 | break;
125 | }
126 | }
127 |
128 | return cardAttachment;
129 | }
130 |
131 | private static string GetCardActionInvokeValue(WikiHelperSearchResult wikiResult)
132 | {
133 | InvokeValue invokeValue = new InvokeValue(wikiResult.imageUrl, wikiResult.text, wikiResult.highlightedTitle);
134 | return JsonConvert.SerializeObject(invokeValue);
135 | }
136 |
137 | ///
138 | /// Parse the invoke request json and returned the invoke value
139 | ///
140 | ///
141 | ///
142 | public static string ParseInvokeRequestJson(string inputString)
143 | {
144 | JObject invokeObjects = JObject.Parse(inputString);
145 |
146 | if (invokeObjects.Count > 0)
147 | {
148 | return invokeObjects[Strings.InvokeRequestJsonKey].Value();
149 | }
150 |
151 | return null;
152 | }
153 |
154 | ///
155 | /// Parse the Update card message back json value returned the updated counter
156 | ///
157 | ///
158 | ///
159 | public static int ParseUpdateCounterJson(Activity activity)
160 | {
161 | if (activity != null && activity.Value != null)
162 | {
163 | JObject invokeObjects = activity.Value as JObject;
164 |
165 | if (invokeObjects != null && invokeObjects.Count > 0)
166 | {
167 | return invokeObjects["updateKey"].Value();
168 | }
169 | }
170 |
171 | return 0;
172 | }
173 |
174 | public static async Task GetBotUserDataObject(IBotDataStore botDataStore, Activity activity)
175 | {
176 | IAddress key = Address.FromActivity(activity);
177 | BotData botData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, CancellationToken.None);
178 | return botData;
179 | }
180 |
181 | public static async Task SaveBotUserDataObject(IBotDataStore botDataStore, Activity activity, BotData userData)
182 | {
183 | IAddress key = Address.FromActivity(activity);
184 | await botDataStore.SaveAsync(key, BotStoreType.BotUserData, userData, CancellationToken.None);
185 | }
186 | }
187 |
188 | public class InvokeValue
189 | {
190 | public string imageUrl { get; set; }
191 | public string text { get; set; }
192 | public string highlightedTitle { get; set; }
193 |
194 | public InvokeValue(string urlValue, string textValue, string highlightedTitleValue)
195 | {
196 | imageUrl = urlValue;
197 | text = textValue;
198 | highlightedTitle = highlightedTitleValue;
199 | }
200 | }
201 | }
--------------------------------------------------------------------------------