microsoft/teams.net

Public

mirrored from https://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
kavin/conversation-fix

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/src/Microsoft.Teams.Bot.Apps/Schema/Invokes/MessageExtensionResponse.cs

359lines · modecode

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