microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
aamirj/ConversationalClient

Branches

Tags

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

Clone

HTTPS

Download ZIP

Libraries/Microsoft.Teams.Api/Activities/Activity.cs

463lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT License.
3
4using System.Text.Json;
5using System.Text.Json.Serialization;
6
7using Microsoft.Teams.Api.Entities;
8using Microsoft.Teams.Common;
9
10namespace Microsoft.Teams.Api.Activities;
11
12[JsonConverter(typeof(JsonConverter<ActivityType>))]
13public partial class ActivityType(string value) : StringEnum(value)
14{
15 public Type ToType()
16 {
17 if (IsTyping) return typeof(TypingActivity);
18 if (IsCommand) return typeof(CommandActivity);
19 if (IsCommandResult) return typeof(CommandResultActivity);
20 if (IsConversationUpdate) return typeof(ConversationUpdateActivity);
21 if (IsEndOfConversation) return typeof(EndOfConversationActivity);
22 if (IsInstallUpdate) return typeof(InstallUpdateActivity);
23 if (IsMessage) return typeof(MessageActivity);
24 if (IsMessageUpdate) return typeof(MessageUpdateActivity);
25 if (IsMessageDelete) return typeof(MessageDeleteActivity);
26 if (IsMessageReaction) return typeof(MessageReactionActivity);
27 if (IsEvent) return typeof(EventActivity);
28 if (IsInvoke) return typeof(InvokeActivity);
29 return typeof(Activity);
30 }
31
32 public string ToPrettyString()
33 {
34 var value = ToString();
35 return $"{value.First().ToString().ToUpper()}{value.AsSpan(1).ToString()}";
36 }
37}
38
39[JsonConverter(typeof(ActivityJsonConverter))]
40public partial interface IActivity : IConvertible, ICloneable
41{
42 public string Id { get; set; }
43
44 public ActivityType Type { get; set; }
45
46 public string? ReplyToId { get; set; }
47
48 public ChannelId ChannelId { get; set; }
49
50 public Account From { get; set; }
51
52 public Account Recipient { get; set; }
53
54 public Conversation Conversation { get; set; }
55
56 public ConversationReference? RelatesTo { get; set; }
57
58 public string? ServiceUrl { get; set; }
59
60 public string? Locale { get; set; }
61
62 public DateTime? Timestamp { get; set; }
63
64 public DateTime? LocalTimestamp { get; set; }
65
66 public IList<IEntity>? Entities { get; set; }
67
68 public ChannelData? ChannelData { get; set; }
69
70 public IDictionary<string, object?> Properties { get; set; }
71
72 /// <summary>
73 /// is this a streaming activity
74 /// </summary>
75 [JsonIgnore]
76 public bool IsStreaming { get; }
77
78 /// <summary>
79 /// get the activity type/name path
80 /// </summary>
81 public string GetPath();
82
83 /// <summary>
84 /// get the quote reply string form of this activity
85 /// </summary>
86 public string ToQuoteReply();
87}
88
89[JsonConverter(typeof(ActivityJsonConverter))]
90public partial class Activity : IActivity
91{
92 [JsonPropertyName("id")]
93 [JsonPropertyOrder(0)]
94 public string Id { get; set; }
95
96 [JsonPropertyName("type")]
97 [JsonPropertyOrder(10)]
98 public ActivityType Type { get; set; }
99
100 [JsonPropertyName("replyToId")]
101 [JsonPropertyOrder(20)]
102 public string? ReplyToId { get; set; }
103
104 [JsonPropertyName("channelId")]
105 [JsonPropertyOrder(30)]
106 public ChannelId ChannelId { get; set; } = ChannelId.MsTeams;
107
108 [JsonPropertyName("from")]
109 [JsonPropertyOrder(40)]
110 public Account From { get; set; }
111
112 [JsonPropertyName("recipient")]
113 [JsonPropertyOrder(50)]
114 public Account Recipient { get; set; }
115
116 [JsonPropertyName("conversation")]
117 [JsonPropertyOrder(60)]
118 public Conversation Conversation { get; set; }
119
120 [JsonPropertyName("relatesTo")]
121 [JsonPropertyOrder(70)]
122 public ConversationReference? RelatesTo { get; set; }
123
124 [JsonPropertyName("serviceUrl")]
125 [JsonPropertyOrder(80)]
126 public string? ServiceUrl { get; set; }
127
128 [JsonPropertyName("locale")]
129 [JsonPropertyOrder(90)]
130 public string? Locale { get; set; }
131
132 [JsonPropertyName("timestamp")]
133 [JsonPropertyOrder(100)]
134 public DateTime? Timestamp { get; set; }
135
136 [JsonPropertyName("localTimestamp")]
137 [JsonPropertyOrder(110)]
138 public DateTime? LocalTimestamp { get; set; }
139
140 [JsonPropertyName("entities")]
141 [JsonPropertyOrder(120)]
142 public IList<IEntity>? Entities { get; set; }
143
144 [JsonPropertyName("channelData")]
145 [JsonPropertyOrder(130)]
146 public ChannelData? ChannelData { get; set; }
147
148 [JsonExtensionData]
149 public IDictionary<string, object?> Properties { get; set; } = new Dictionary<string, object?>();
150
151 [JsonConstructor]
152 public Activity(string type)
153 {
154 Type = new(type);
155 }
156
157 public Activity(ActivityType type)
158 {
159 Type = type;
160 }
161
162 public Activity(IActivity activity)
163 {
164 Id = activity.Id;
165 Type = activity.Type;
166 ReplyToId = activity.ReplyToId;
167 ChannelId = activity.ChannelId;
168 From = activity.From;
169 Recipient = activity.Recipient;
170 Conversation = activity.Conversation;
171 RelatesTo = activity.RelatesTo;
172 ServiceUrl = activity.ServiceUrl;
173 Locale = activity.Locale;
174 Timestamp = activity.Timestamp;
175 LocalTimestamp = activity.LocalTimestamp;
176 Entities = activity.Entities;
177 ChannelData = activity.ChannelData;
178 Properties = activity.Properties;
179 }
180
181 [JsonIgnore]
182 public bool IsStreaming => Entities?.Any(entity => entity.Type == "streaminfo" && entity is StreamInfoEntity) ?? false;
183
184 public object Clone() => MemberwiseClone();
185 public virtual Activity Copy() => (Activity)Clone();
186 public virtual string GetPath() => string.Join(".", ["Activity", Type.ToPrettyString()]);
187
188 public virtual Activity WithId(string value)
189 {
190 Id = value;
191 return this;
192 }
193
194 public virtual Activity WithReplyToId(string value)
195 {
196 ReplyToId = value;
197 return this;
198 }
199
200 public virtual Activity WithChannelId(ChannelId value)
201 {
202 ChannelId = value;
203 return this;
204 }
205
206 public virtual Activity WithFrom(Account value)
207 {
208 From = value;
209 return this;
210 }
211
212 public virtual Activity WithConversation(Conversation value)
213 {
214 Conversation = value;
215 return this;
216 }
217
218 public virtual Activity WithRelatesTo(ConversationReference value)
219 {
220 RelatesTo = value;
221 return this;
222 }
223
224 public virtual Activity WithRecipient(Account value)
225 {
226 Recipient = value;
227 return this;
228 }
229
230 public virtual Activity WithServiceUrl(string value)
231 {
232 ServiceUrl = value;
233 return this;
234 }
235
236 public virtual Activity WithTimestamp(DateTime value)
237 {
238 Timestamp = value;
239 return this;
240 }
241
242 public virtual Activity WithLocale(string value)
243 {
244 Locale = value;
245 return this;
246 }
247
248 public virtual Activity WithLocalTimestamp(DateTime value)
249 {
250 LocalTimestamp = value;
251 return this;
252 }
253
254 public virtual Activity WithData(ChannelData value)
255 {
256 ChannelData ??= new();
257 ChannelData.Merge(value);
258 return this;
259 }
260
261 public virtual Activity WithData(string key, object? value)
262 {
263 ChannelData ??= new();
264 ChannelData.Properties[key] = value;
265 return this;
266 }
267
268 public virtual Activity WithAppId(string value)
269 {
270 ChannelData ??= new();
271 ChannelData.App ??= new App() { Id = value };
272 return this;
273 }
274
275 /// <summary>
276 /// add an entity
277 /// </summary>
278 public virtual Activity AddEntity(params IEntity[] entities)
279 {
280 Entities ??= [];
281
282 foreach (var entity in entities)
283 {
284 Entities.Add(entity);
285 }
286
287 return this;
288 }
289
290 public virtual Activity UpdateEntity(IEntity oldEntity, IEntity newEntity)
291 {
292 if (Entities != null)
293 {
294 Entities.Remove(oldEntity);
295 }
296 else
297 {
298 Entities = [];
299 }
300
301 Entities.Add(newEntity);
302 return this;
303 }
304
305 /// <summary>
306 /// ensures a single root level message entity exists
307 /// </summary>
308 private IMessageEntity GetRootLevelMessageEntity()
309 {
310 var messageEntity = Entities?.FirstOrDefault(
311 e => e.Type == "https://schema.org/Message" && e.OType == "Message"
312 ) as IMessageEntity;
313
314 if (messageEntity is null)
315 {
316 messageEntity = new MessageEntity()
317 {
318 Type = "https://schema.org/Message",
319 OType = "Message",
320 OContext = "https://schema.org"
321 };
322
323 AddEntity(messageEntity);
324 }
325
326 return messageEntity;
327 }
328
329 /// <summary>
330 /// add the `Generated By AI` label
331 /// </summary>
332 public virtual Activity AddAIGenerated()
333 {
334 var messageEntity = GetRootLevelMessageEntity();
335 messageEntity.AdditionalType ??= [];
336
337 if (!messageEntity.AdditionalType.Contains("AIGeneratedContent"))
338 {
339 messageEntity.AdditionalType.Add("AIGeneratedContent");
340 }
341
342 return this;
343 }
344
345 /// <summary>
346 /// add content sensitivity label
347 /// </summary>
348 /// <param name="name">the content title</param>
349 /// <param name="description">the content description</param>
350 /// <param name="pattern">the pattern</param>
351 public virtual Activity AddSensitivityLabel(string name, string? description = null, DefinedTerm? pattern = null)
352 {
353 return AddEntity(new SensitiveUsageEntity()
354 {
355 Name = name,
356 Description = description,
357 Pattern = pattern
358 });
359 }
360
361 /// <summary>
362 /// enable/disable message feedback
363 /// </summary>
364 public virtual Activity AddFeedback(bool value = true)
365 {
366 ChannelData ??= new();
367 ChannelData.FeedbackLoopEnabled = value;
368 return this;
369 }
370
371 /// <summary>
372 /// add a citation
373 /// </summary>
374 public virtual Activity AddCitation(int position, CitationAppearance appearance)
375 {
376 var messageEntity = GetRootLevelMessageEntity();
377 var citationEntity = new CitationEntity(messageEntity);
378 citationEntity.Citation ??= [];
379 citationEntity.Citation.Add(new CitationEntity.Claim()
380 {
381 Position = position,
382 Appearance = appearance.ToDocument()
383 });
384
385 UpdateEntity(messageEntity, citationEntity);
386 return this;
387 }
388
389 public CommandActivity ToCommand() => (CommandActivity)this;
390 public CommandResultActivity ToCommandResult() => (CommandResultActivity)this;
391 public TypingActivity ToTyping() => (TypingActivity)this;
392 public InstallUpdateActivity ToInstallUpdate() => (InstallUpdateActivity)this;
393 public MessageActivity ToMessage() => (MessageActivity)this;
394 public MessageUpdateActivity ToMessageUpdate() => (MessageUpdateActivity)this;
395 public MessageDeleteActivity ToMessageDelete() => (MessageDeleteActivity)this;
396 public MessageReactionActivity ToMessageReaction() => (MessageReactionActivity)this;
397 public ConversationUpdateActivity ToConversationUpdate() => (ConversationUpdateActivity)this;
398 public EndOfConversationActivity ToEndOfConversation() => (EndOfConversationActivity)this;
399 public EventActivity ToEvent() => (EventActivity)this;
400 public InvokeActivity ToInvoke() => (InvokeActivity)this;
401
402 public Activity Merge(Activity from)
403 {
404 Id ??= from.Id;
405 ReplyToId ??= from.ReplyToId;
406 ChannelId ??= from.ChannelId;
407 From ??= from.From;
408 Recipient ??= from.Recipient;
409 Conversation ??= from.Conversation;
410 RelatesTo ??= from.RelatesTo;
411 ServiceUrl ??= from.ServiceUrl;
412 Locale ??= from.Locale;
413 Timestamp ??= from.Timestamp;
414 LocalTimestamp ??= from.LocalTimestamp;
415 AddEntity(from.Entities?.ToArray() ?? []);
416
417 if (from.ChannelData is not null)
418 {
419 WithData(from.ChannelData);
420 }
421
422 if (from.Properties is not null)
423 {
424 Properties ??= new Dictionary<string, object?>();
425
426 foreach (var kv in from.Properties)
427 {
428 Properties[kv.Key] = kv.Value;
429 }
430 }
431
432 return this;
433 }
434
435 public string ToQuoteReply()
436 {
437 var text = string.Empty;
438
439 if (this is MessageActivity message)
440 {
441 text = $"<p itemprop=\"preview\">{message.Text}</p>";
442 }
443
444 return $"""
445 <blockquote itemscope="" itemtype="http://schema.skype.com/Reply" itemid="{Id}">
446 <strong itemprop="mri" itemid="{From.Id}">
447 {From.Name}
448 </strong>
449 <span itemprop="time" itemid="{Id}"></span>
450 {text}
451 </blockquote>
452 """;
453 }
454
455 public override string ToString()
456 {
457 return JsonSerializer.Serialize(this, new JsonSerializerOptions()
458 {
459 WriteIndented = true,
460 DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
461 });
462 }
463}