microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
682a2b33e7a9062b703cd1f0ffeb0b7b80ea504c

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

core/samples/MessageExtensionBot/Program.cs

263lines ยท modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json;
5using MessageExtensionBot;
6using Microsoft.Teams.Bot.Apps;
7using Microsoft.Teams.Bot.Apps.Handlers;
8using Microsoft.Teams.Bot.Apps.Schema;
9
10WebApplicationBuilder webAppBuilder = WebApplication.CreateSlimBuilder(args);
11webAppBuilder.Services.AddTeamsBotApplication();
12WebApplication webApp = webAppBuilder.Build();
13
14TeamsBotApplication bot = webApp.UseTeamsBotApplication();
15
16// ==================== MESSAGE EXTENSION QUERY ====================
17bot.OnQuery(async (context, cancellationToken) =>
18{
19 Console.WriteLine("โœ“ OnQuery");
20
21 MessageExtensionQuery? query = context.Activity.Value;
22 string commandId = query?.CommandId ?? "unknown";
23 string searchText = query?.Parameters
24 .FirstOrDefault(p => !p.Name.Equals("initialRun"))?
25 .Value ?? "default";
26
27 if (searchText.Equals("help", StringComparison.OrdinalIgnoreCase))
28 {
29 return MessageExtensionResponse.CreateBuilder()
30 .WithType(MessageExtensionResponseType.Message)
31 .WithText("๐Ÿ’ก Search for any keyword to see results.")
32 .Build();
33 }
34
35 // Create results with tap actions to trigger OnSelectItem
36 object[] cards = Cards.CreateQueryResultCards(searchText);
37 TeamsAttachment[] attachments = [.. cards.Select(card => TeamsAttachment.CreateBuilder().WithContent(card)
38 .WithContentType(AttachmentContentType.ThumbnailCard).Build())];
39
40 return MessageExtensionResponse.CreateBuilder()
41 .WithType(MessageExtensionResponseType.Result)
42 .WithAttachmentLayout(TeamsAttachmentLayout.List)
43 .WithAttachments(attachments)
44 .Build();
45});
46
47// ==================== MESSAGE EXTENSION SELECT ITEM ====================
48bot.OnSelectItem(async (context, cancellationToken) =>
49{
50 Console.WriteLine("โœ“ OnSelectItem");
51
52 JsonElement selectedItem = context.Activity.Value;
53 JsonElement? itemData = selectedItem;
54 string? itemId = itemData.Value.TryGetProperty("itemId", out JsonElement id) ? id.GetString() : "unknown";
55 string? title = itemData.Value.TryGetProperty("title", out JsonElement t) ? t.GetString() : "Selected Item";
56 string? description = itemData.Value.TryGetProperty("description", out JsonElement d) ? d.GetString() : "No description";
57
58 object card = Cards.CreateSelectItemCard(itemId, title, description);
59 TeamsAttachment attachment = TeamsAttachment.CreateBuilder().WithAdaptiveCard(card).Build();
60
61 return MessageExtensionResponse.CreateBuilder()
62 .WithType(MessageExtensionResponseType.Result)
63 .WithAttachmentLayout(TeamsAttachmentLayout.List)
64 .WithAttachments(attachment)
65 .Build();
66});
67
68// ==================== MESSAGE EXTENSION FETCH TASK ====================
69bot.OnFetchTask(async (context, cancellationToken) =>
70{
71 Console.WriteLine("โœ“ OnFetchTask");
72
73 MessageExtensionAction? action = context.Activity.Value;
74
75 object fetchTaskCard = Cards.CreateFetchTaskCard(action?.CommandId ?? "unknown");
76 TeamsAttachment fetchTaskCardResponse = TeamsAttachment.CreateBuilder()
77 .WithAdaptiveCard(fetchTaskCard).Build();
78 return MessageExtensionActionResponse.CreateBuilder()
79 .WithTask(TaskModuleResponse.CreateBuilder()
80 .WithType(TaskModuleResponseType.Continue)
81 .WithTitle("Task Module")
82 .WithCard(fetchTaskCardResponse))
83 .Build();
84});
85
86// Helper: Extract title and description from preview card
87static (string?, string?) GetDataFromPreview(TeamsActivity? preview)
88{
89 if (preview?.Attachments == null) return (null, null);
90
91 JsonElement cardData = JsonSerializer.Deserialize<JsonElement>(
92 JsonSerializer.Serialize(preview.Attachments[0].Content));
93
94 if (!cardData.TryGetProperty("body", out JsonElement body) || body.ValueKind != JsonValueKind.Array)
95 return (null, null);
96
97 string? title = body.GetArrayLength() > 0 && body[0].TryGetProperty("text", out JsonElement t) ? t.GetString() : null;
98 string? description = body.GetArrayLength() > 1 && body[1].TryGetProperty("text", out JsonElement d) ? d.GetString() : null;
99
100 return (title, description);
101}
102
103
104// ==================== MESSAGE EXTENSION SUBMIT ACTION ====================
105bot.OnSubmitAction(async (context, cancellationToken) =>
106{
107 Console.WriteLine("โœ“ OnSubmitAction");
108
109 MessageExtensionAction? action = context.Activity.Value;
110
111 // Handle "edit" - user clicked edit on the preview, show the form again
112 if (action?.BotMessagePreviewAction == "edit")
113 {
114 Console.WriteLine("Handling EDIT action - returning to form");
115 (string? previewTitle, string? previewDescription) = GetDataFromPreview(action.BotActivityPreview?.FirstOrDefault());
116
117 object editFormCard = Cards.CreateEditFormCard(previewTitle, previewDescription);
118 TeamsAttachment editFormCardResponse = TeamsAttachment.CreateBuilder()
119 .WithAdaptiveCard(editFormCard).Build();
120 return MessageExtensionActionResponse.CreateBuilder()
121 .WithTask(TaskModuleResponse.CreateBuilder()
122 .WithType(TaskModuleResponseType.Continue)
123 .WithTitle("Edit Card")
124 .WithCard(editFormCardResponse))
125 .Build();
126 }
127
128 // Handle "send" - user clicked send on the preview, finalize the card
129 //TODO : when I start from the compose box or message, i get an error at this point but seems to be a teams issue ( no activity is sent on clicking send)
130 if (action?.BotMessagePreviewAction == "send")
131 {
132 Console.WriteLine("Handling SEND action - finalizing card");
133 (string? previewTitle, string? previewDescription) = GetDataFromPreview(action.BotActivityPreview?.FirstOrDefault());
134
135 object card = Cards.CreateSubmitActionCard(previewTitle, previewDescription);
136 TeamsAttachment attachment2 = TeamsAttachment.CreateBuilder().WithAdaptiveCard(card).Build();
137
138 return MessageExtensionActionResponse.CreateBuilder()
139 .WithComposeExtension(MessageExtensionResponse.CreateBuilder()
140 .WithType(MessageExtensionResponseType.Result)
141 .WithAttachmentLayout(TeamsAttachmentLayout.List)
142 .WithAttachments(attachment2))
143 .Build();
144 }
145
146
147 JsonElement? data = action?.Data as JsonElement?;
148 string? title = data != null && data.Value.TryGetProperty("title", out JsonElement t) ? t.GetString() : "Untitled";
149 string? description = data != null && data.Value.TryGetProperty("description", out JsonElement d) ? d.GetString() : "No description";
150
151 object previewCard = Cards.CreateSubmitActionCard(title, description);
152 TeamsAttachment attachment = TeamsAttachment.CreateBuilder().WithAdaptiveCard(previewCard).Build();
153
154 return MessageExtensionActionResponse.CreateBuilder()
155 .WithComposeExtension(MessageExtensionResponse.CreateBuilder()
156 .WithType(MessageExtensionResponseType.BotMessagePreview)
157 .WithActivityPreview(new MessageActivity([attachment]))
158 )
159 .Build();
160});
161
162// ==================== MESSAGE EXTENSION QUERY LINK ====================
163bot.OnQueryLink(async (context, cancellationToken) =>
164{
165 Console.WriteLine("โœ“ OnQueryLink");
166
167 MessageExtensionQueryLink? queryLink = context.Activity.Value;
168
169 object card = Cards.CreateLinkUnfurlCard(queryLink?.Url?.ToString());
170 TeamsAttachment attachment = TeamsAttachment.CreateBuilder()
171 .WithContent(card).WithContentType(AttachmentContentType.ThumbnailCard).Build();
172
173 return MessageExtensionResponse.CreateBuilder()
174 .WithType(MessageExtensionResponseType.Result)
175 .WithAttachmentLayout(TeamsAttachmentLayout.List)
176 .WithAttachments(attachment)
177 .Build();
178});
179
180// ==================== MESSAGE EXTENSION ANON QUERY LINK ====================
181//TODO : difficult to test, app must be published to catalog
182bot.OnAnonQueryLink(async (context, cancellationToken) =>
183{
184 Console.WriteLine("โœ“ OnAnonQueryLink");
185
186 MessageExtensionQueryLink? anonQueryLink = context.Activity.Value;
187 if (anonQueryLink != null)
188 {
189 Console.WriteLine($" URL: '{anonQueryLink.Url}'");
190 }
191
192 object card = Cards.CreateLinkUnfurlCard(anonQueryLink?.Url?.ToString());
193 TeamsAttachment attachment = TeamsAttachment.CreateBuilder()
194 .WithContent(card).WithContentType(AttachmentContentType.ThumbnailCard).Build();
195
196 return MessageExtensionResponse.CreateBuilder()
197 .WithType(MessageExtensionResponseType.Result)
198 .WithAttachmentLayout(TeamsAttachmentLayout.List)
199 .WithAttachments(attachment)
200 .Build();
201});
202
203
204// ==================== MESSAGE EXTENSION QUERY SETTING URL ====================
205bot.OnQuerySettingUrl(async (context, cancellationToken) =>
206{
207 Console.WriteLine("โœ“ OnQuerySettingUrl");
208
209 MessageExtensionQuery? query = context.Activity.Value;
210
211 var action = new
212 {
213 Type = "openUrl",
214 Value = "https://www.microsoft.com"
215 };
216
217 return MessageExtensionResponse.CreateBuilder()
218 .WithType(MessageExtensionResponseType.Config)
219 .WithSuggestedActions([action])
220 .Build();
221});
222
223
224//TODO : this is deprecated ?
225// ==================== MESSAGE EXTENSION CARD BUTTON CLICKED ====================
226//bot.OnCardButtonClicked(async (context, cancellationToken) =>
227//{
228// Console.WriteLine("โœ“ OnCardButtonClicked");
229// Console.WriteLine($" Activity Type: {context.Activity.GetType().Name}");
230//
231// return new CoreInvokeResponse(200);
232//});
233
234//TODO : only able to get OnQuerySettingUrl activity, how do we get onSetting or OnConfigFetch
235/*
236// ==================== MESSAGE EXTENSION SETTING ====================
237bot.OnSetting(async (context, cancellationToken) =>
238{
239 Console.WriteLine("โœ“ OnSetting");
240
241 var query = context.Activity.Value;
242 if (query != null)
243 {
244 Console.WriteLine($" Command ID: '{query.CommandId}'");
245 }
246
247 var action = new MessagingExtensionAction
248 {
249 Type = "openUrl",
250 Value = "https://microsoft.com",
251 Title = "Configure Settings"
252 };
253
254 var response = MessagingExtensionResponse.CreateBuilder()
255 .WithType(MessagingExtensionResponseType.Config)
256 .WithSuggestedActions(action)
257 .Build();
258
259 return new CoreInvokeResponse<MessageExtensionResponse>(200, response);
260});
261*/
262
263webApp.Run();
264