microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
samples/migration-bot

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/src/Microsoft.Teams.Bot.Apps/Handlers/MessageExtension/MessageExtensionResponse.cs

360lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json.Serialization;
5using Microsoft.Teams.Bot.Apps.Schema;
6
7namespace Microsoft.Teams.Bot.Apps.Handlers.MessageExtension;
8
9/// <summary>
10/// Messaging extension response types.
11/// </summary>
12public static class MessageExtensionResponseType
13{
14 /// <summary>
15 /// Result type - displays a list of search results.
16 /// </summary>
17 public const string Result = "result";
18
19 /// <summary>
20 /// Message type - displays a plain text message.
21 /// </summary>
22 public const string Message = "message";
23
24 /// <summary>
25 /// Bot message preview type - shows a preview that can be edited before sending.
26 /// </summary>
27 public const string BotMessagePreview = "botMessagePreview";
28
29 /// <summary>
30 /// Config type - prompts the user to set up the message extension.
31 /// </summary>
32 public const string Config = "config";
33
34 //TODO : review
35 /*
36 /// <summary>
37 /// Auth type - prompts the user to authenticate.
38 /// </summary>
39 public const string Auth = "auth";
40 */
41}
42
43/// <summary>
44/// Messaging extension response wrapper.
45/// </summary>
46public class MessageExtensionResponse
47{
48 /// <summary>
49 /// The compose extension result (for message extension results, auth, config, etc.).
50 /// </summary>
51 [JsonPropertyName("composeExtension")]
52 [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
53 public ComposeExtension? ComposeExtension { get; set; }
54
55 /// <summary>
56 /// Creates a new builder for MessagingExtensionResponse.
57 /// </summary>
58 public static MessageExtensionResponseBuilder CreateBuilder()
59 {
60 return new MessageExtensionResponseBuilder();
61 }
62}
63
64
65/// <summary>
66/// Messaging extension result.
67/// </summary>
68public class ComposeExtension
69{
70 /// <summary>
71 /// Type of result.
72 /// See <see cref="MessageExtensionResponseType"/> for common values.
73 /// </summary>
74 [JsonPropertyName("type")]
75 public string? Type { get; set; }
76
77 /// <summary>
78 /// Layout for attachments.
79 /// See <see cref="TeamsAttachmentLayout"/> for common values.
80 /// </summary>
81 [JsonPropertyName("attachmentLayout")]
82 public string? AttachmentLayout { get; set; }
83
84 /// <summary>
85 /// Array of attachments (cards) to display.
86 /// </summary>
87 // TODO : there is an extra preview field but when is it used ?
88 [JsonPropertyName("attachments")]
89 public IList<TeamsAttachment>? Attachments { get; set; }
90
91 /// <summary>
92 /// Text to display.
93 /// </summary>
94 [JsonPropertyName("text")]
95 public string? Text { get; set; }
96
97 /// <summary>
98 /// Activity preview for bot message preview.
99 /// </summary>
100 //TODO : this needs to be activity type or something else - format is type, attachments[]
101 [JsonPropertyName("activityPreview")]
102 public TeamsActivity? ActivityPreview { get; set; }
103
104 /// <summary>
105 /// Suggested actions for config type.
106 /// </summary>
107 [JsonPropertyName("suggestedActions")]
108 public MessageExtensionSuggestedAction? SuggestedActions { get; set; }
109}
110
111/// <summary>
112/// Suggested actions for messaging extension configuration.
113/// </summary>
114public class MessageExtensionSuggestedAction
115{
116 //TODO : this should come from cards package
117
118 /// <summary>
119 /// Array of actions.
120 /// </summary>
121 [JsonPropertyName("actions")]
122 public IList<object>? Actions { get; set; }
123}
124
125
126/// <summary>
127/// Builder for MessagingExtensionResponse.
128/// </summary>
129public class MessageExtensionResponseBuilder
130{
131 private string? _type;
132 private string? _attachmentLayout;
133 private TeamsAttachment[]? _attachments;
134 private TeamsActivity? _activityPreview;
135 private object[]? _suggestedActions;
136 private string? _text;
137
138 /// <summary>
139 /// Sets the type of the response. Common values: "result", "auth", "config", "message", "botMessagePreview".
140 /// </summary>
141 public MessageExtensionResponseBuilder WithType(string type)
142 {
143 _type = type;
144 return this;
145 }
146
147 /// <summary>
148 /// Sets the attachment layout. Common values: "list", "grid".
149 /// </summary>
150 public MessageExtensionResponseBuilder WithAttachmentLayout(string layout)
151 {
152 _attachmentLayout = layout;
153 return this;
154 }
155
156 /// <summary>
157 /// Sets the attachments for the response.
158 /// </summary>
159 public MessageExtensionResponseBuilder WithAttachments(params TeamsAttachment[] attachments)
160 {
161 _attachments = attachments;
162 return this;
163 }
164
165 /// <summary>
166 /// Sets the activity preview for bot message preview type.
167 /// </summary>
168 public MessageExtensionResponseBuilder WithActivityPreview(TeamsActivity activityPreview)
169 {
170 _activityPreview = activityPreview;
171 return this;
172 }
173
174 /// <summary>
175 /// Sets suggested actions for config type.
176 /// </summary>
177 public MessageExtensionResponseBuilder WithSuggestedActions(params object[] actions)
178 {
179 _suggestedActions = actions;
180 return this;
181 }
182
183 /// <summary>
184 /// Sets the text message for message type.
185 /// </summary>
186 public MessageExtensionResponseBuilder WithText(string text)
187 {
188 _text = text;
189 return this;
190 }
191
192 /// <summary>
193 /// Validates and builds the MessagingExtensionResponse.
194 /// </summary>
195 internal MessageExtensionResponse Validate()
196 {
197 if (string.IsNullOrEmpty(_type))
198 {
199 throw new InvalidOperationException("Type must be set. Use WithType() to specify MessageExtensionResponseType.Result, Message, BotMessagePreview, or Config.");
200 }
201
202 return _type switch
203 {
204 MessageExtensionResponseType.Result => ValidateResultType(),
205 MessageExtensionResponseType.Message => ValidateMessageType(),
206 MessageExtensionResponseType.BotMessagePreview => ValidateBotMessagePreviewType(),
207 MessageExtensionResponseType.Config => ValidateConfigType(),
208 _ => throw new InvalidOperationException($"Unknown message extension response type: {_type}")
209 };
210 }
211
212 private MessageExtensionResponse ValidateResultType()
213 {
214 if (_attachments == null || _attachments.Length == 0)
215 {
216 throw new InvalidOperationException("Attachments must be set for Result type. Use WithAttachments().");
217 }
218
219 if (!string.IsNullOrEmpty(_text))
220 {
221 throw new InvalidOperationException("Text cannot be set for Result type. Text is only used with Message type.");
222 }
223
224 if (_activityPreview != null)
225 {
226 throw new InvalidOperationException("ActivityPreview cannot be set for Result type. ActivityPreview is only used with BotMessagePreview type.");
227 }
228
229 if (_suggestedActions != null)
230 {
231 throw new InvalidOperationException("SuggestedActions cannot be set for Result type. SuggestedActions is only used with Config type.");
232 }
233
234 return new MessageExtensionResponse
235 {
236 ComposeExtension = new ComposeExtension
237 {
238 Type = _type,
239 AttachmentLayout = _attachmentLayout,
240 Attachments = _attachments
241 }
242 };
243 }
244
245 private MessageExtensionResponse ValidateMessageType()
246 {
247 if (string.IsNullOrEmpty(_text))
248 {
249 throw new InvalidOperationException("Text must be set for Message type. Use WithText().");
250 }
251
252 if (_attachments != null)
253 {
254 throw new InvalidOperationException("Attachments cannot be set for Message type. Attachments is only used with Result or BotMessagePreview type.");
255 }
256
257 if (!string.IsNullOrEmpty(_attachmentLayout))
258 {
259 throw new InvalidOperationException("AttachmentLayout cannot be set for Message type. AttachmentLayout is only used with Result type.");
260 }
261
262 if (_activityPreview != null)
263 {
264 throw new InvalidOperationException("ActivityPreview cannot be set for Message type. ActivityPreview is only used with BotMessagePreview type.");
265 }
266
267 if (_suggestedActions != null)
268 {
269 throw new InvalidOperationException("SuggestedActions cannot be set for Message type. SuggestedActions is only used with Config type.");
270 }
271
272 return new MessageExtensionResponse
273 {
274 ComposeExtension = new ComposeExtension
275 {
276 Type = _type,
277 Text = _text
278 }
279 };
280 }
281
282 private MessageExtensionResponse ValidateBotMessagePreviewType()
283 {
284 if (_activityPreview == null)
285 {
286 throw new InvalidOperationException("ActivityPreview must be set for BotMessagePreview type. Use WithActivityPreview().");
287 }
288
289 if (!string.IsNullOrEmpty(_text))
290 {
291 throw new InvalidOperationException("Text cannot be set for BotMessagePreview type. Text is only used with Message type.");
292 }
293
294 if (!string.IsNullOrEmpty(_attachmentLayout))
295 {
296 throw new InvalidOperationException("AttachmentLayout cannot be set for BotMessagePreview type. AttachmentLayout is only used with Result type.");
297 }
298
299 if (_suggestedActions != null)
300 {
301 throw new InvalidOperationException("SuggestedActions cannot be set for BotMessagePreview type. SuggestedActions is only used with Config type.");
302 }
303
304 return new MessageExtensionResponse
305 {
306 ComposeExtension = new ComposeExtension
307 {
308 Type = _type,
309 ActivityPreview = _activityPreview,
310 Attachments = _attachments
311 }
312 };
313 }
314
315 private MessageExtensionResponse ValidateConfigType()
316 {
317 if (_suggestedActions == null || _suggestedActions.Length == 0)
318 {
319 throw new InvalidOperationException("SuggestedActions must be set for Config type. Use WithSuggestedActions().");
320 }
321
322 if (_attachments != null)
323 {
324 throw new InvalidOperationException("Attachments cannot be set for Config type. Attachments is only used with Result or BotMessagePreview type.");
325 }
326
327 if (!string.IsNullOrEmpty(_attachmentLayout))
328 {
329 throw new InvalidOperationException("AttachmentLayout cannot be set for Config type. AttachmentLayout is only used with Result type.");
330 }
331
332 if (!string.IsNullOrEmpty(_text))
333 {
334 throw new InvalidOperationException("Text cannot be set for Config type. Text is only used with Message type.");
335 }
336
337 if (_activityPreview != null)
338 {
339 throw new InvalidOperationException("ActivityPreview cannot be set for Config type. ActivityPreview is only used with BotMessagePreview type.");
340 }
341
342 return new MessageExtensionResponse
343 {
344 ComposeExtension = new ComposeExtension
345 {
346 Type = _type,
347 SuggestedActions = new MessageExtensionSuggestedAction { Actions = _suggestedActions }
348 }
349 };
350 }
351
352 /// <summary>
353 /// Builds the MessagingExtensionResponse and wraps it in a InvokeResponse.
354 /// </summary>
355 /// <param name="statusCode">The HTTP status code (default: 200).</param>
356 public InvokeResponse<MessageExtensionResponse> Build(int statusCode = 200)
357 {
358 return new InvokeResponse<MessageExtensionResponse>(statusCode, Validate());
359 }
360}
361