microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
6594a29aa91c928c547a8821d305758bc8d340ed

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/samples/MessageExtensionBot/Program.cs

264lines ยท modecode

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