microsoft/teams.net
Publicmirrored from https://github.com/microsoft/teams.netAvailable
core/src/Microsoft.Teams.Bot.Apps/Schema/TeamsActivity.cs
214lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | using System.Text; |
| 5 | using System.Text.Json; |
| 6 | using System.Text.Json.Serialization; |
| 7 | using System.Text.Json.Serialization.Metadata; |
| 8 | using Microsoft.Teams.Bot.Apps.Schema.Entities; |
| 9 | using Microsoft.Teams.Bot.Core.Schema; |
| 10 | |
| 11 | namespace Microsoft.Teams.Bot.Apps.Schema; |
| 12 | |
| 13 | /// <summary> |
| 14 | /// Teams Activity schema. |
| 15 | /// </summary> |
| 16 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2227: Collection Properties should be read only", Justification = "<Pending>")] |
| 17 | public class TeamsActivity : CoreActivity |
| 18 | { |
| 19 | /// <summary> |
| 20 | /// Creates a new instance of the TeamsActivity class from the specified Activity object. |
| 21 | /// </summary> |
| 22 | /// <param name="activity">The Activity instance to convert. Cannot be null.</param> |
| 23 | /// <returns>A TeamsActivity object that represents the specified Activity.</returns> |
| 24 | public static TeamsActivity FromActivity(CoreActivity activity) |
| 25 | { |
| 26 | ArgumentNullException.ThrowIfNull(activity); |
| 27 | |
| 28 | return TeamsActivityType.ActivityDeserializerMap.TryGetValue(activity.Type, out var factory) |
| 29 | ? factory.FromActivity(activity) |
| 30 | : new TeamsActivity(activity); // Fallback to base type |
| 31 | } |
| 32 | |
| 33 | /// <summary> |
| 34 | /// Creates a new instance of the TeamsActivity class from the specified Activity object. |
| 35 | /// </summary> |
| 36 | /// <param name="json"></param> |
| 37 | /// <returns></returns> |
| 38 | public static new TeamsActivity FromJsonString(string json) |
| 39 | { |
| 40 | string? type = null; |
| 41 | var jsonBytes = Encoding.UTF8.GetBytes(json); |
| 42 | var reader = new Utf8JsonReader(jsonBytes); |
| 43 | |
| 44 | while (reader.Read()) |
| 45 | { |
| 46 | if (reader.TokenType == JsonTokenType.PropertyName && |
| 47 | reader.ValueTextEquals("type"u8)) |
| 48 | { |
| 49 | reader.Read(); |
| 50 | type = reader.GetString(); |
| 51 | break; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | return type != null && TeamsActivityType.ActivityDeserializerMap.TryGetValue(type, out var factory) |
| 56 | ? factory.FromJson(json) |
| 57 | : FromJsonString(json, TeamsActivityJsonContext.Default.TeamsActivity); |
| 58 | } |
| 59 | |
| 60 | /// <summary> |
| 61 | /// Creates a new instance of the specified activity type from JSON string. |
| 62 | /// </summary> |
| 63 | /// <typeparam name="T">The expected activity type.</typeparam> |
| 64 | /// <param name="json">The JSON string to deserialize.</param> |
| 65 | /// <param name="typeInfo">The JSON type info for deserialization.</param> |
| 66 | /// <returns>An activity of type T.</returns> |
| 67 | public static T FromJsonString<T>(string json, JsonTypeInfo<T> typeInfo) where T : TeamsActivity |
| 68 | { |
| 69 | T activity = JsonSerializer.Deserialize(json, typeInfo)!; |
| 70 | activity.Rebase(); |
| 71 | return activity; |
| 72 | } |
| 73 | |
| 74 | |
| 75 | /// <summary> |
| 76 | /// Overrides the ToJson method to serialize the TeamsActivity object to a JSON string. |
| 77 | /// </summary> |
| 78 | /// <returns></returns> |
| 79 | public new string ToJson() |
| 80 | => ToJson(TeamsActivityJsonContext.Default.TeamsActivity); |
| 81 | |
| 82 | /// <summary> |
| 83 | /// Constructor with type parameter. |
| 84 | /// </summary> |
| 85 | /// <param name="type"></param> |
| 86 | protected TeamsActivity(string type) : this() |
| 87 | { |
| 88 | Type = type; |
| 89 | } |
| 90 | |
| 91 | /// <summary> |
| 92 | /// Default constructor. |
| 93 | /// </summary> |
| 94 | [JsonConstructor] |
| 95 | public TeamsActivity() |
| 96 | { |
| 97 | From = new TeamsConversationAccount(); |
| 98 | Recipient = new TeamsConversationAccount(); |
| 99 | Conversation = new TeamsConversation(); |
| 100 | } |
| 101 | |
| 102 | /// <summary> |
| 103 | /// Protected constructor to create TeamsActivity from CoreActivity. |
| 104 | /// Allows derived classes to call via base(activity). |
| 105 | /// </summary> |
| 106 | /// <param name="activity">The CoreActivity to convert.</param> |
| 107 | protected TeamsActivity(CoreActivity activity) : base(activity) |
| 108 | { |
| 109 | ArgumentNullException.ThrowIfNull(activity); |
| 110 | // Convert base types to Teams-specific types |
| 111 | if (activity.ChannelData is not null) |
| 112 | { |
| 113 | ChannelData = new TeamsChannelData(activity.ChannelData); |
| 114 | } |
| 115 | From = new TeamsConversationAccount(activity.From); |
| 116 | Recipient = new TeamsConversationAccount(activity.Recipient); |
| 117 | Conversation = new TeamsConversation(activity.Conversation); |
| 118 | Attachments = TeamsAttachment.FromJArray(activity.Attachments); |
| 119 | Entities = EntityList.FromJsonArray(activity.Entities); |
| 120 | |
| 121 | Rebase(); |
| 122 | } |
| 123 | |
| 124 | /// <summary> |
| 125 | /// Resets shadow properties in base class |
| 126 | /// </summary> |
| 127 | /// <returns></returns> |
| 128 | internal TeamsActivity Rebase() |
| 129 | { |
| 130 | base.Attachments = this.Attachments?.ToJsonArray(); |
| 131 | base.Entities = this.Entities?.ToJsonArray(); |
| 132 | |
| 133 | return this; |
| 134 | } |
| 135 | |
| 136 | |
| 137 | /// <summary> |
| 138 | /// Gets or sets the account information for the sender of the Teams conversation. |
| 139 | /// </summary> |
| 140 | [JsonPropertyName("from")] |
| 141 | public new TeamsConversationAccount From |
| 142 | { |
| 143 | get => (base.From as TeamsConversationAccount) ?? new TeamsConversationAccount(base.From); |
| 144 | set => base.From = value; |
| 145 | } |
| 146 | |
| 147 | /// <summary> |
| 148 | /// Gets or sets the account information for the recipient of the Teams conversation. |
| 149 | /// </summary> |
| 150 | [JsonPropertyName("recipient")] |
| 151 | public new TeamsConversationAccount Recipient |
| 152 | { |
| 153 | get => (base.Recipient as TeamsConversationAccount) ?? new TeamsConversationAccount(base.Recipient); |
| 154 | set => base.Recipient = value; |
| 155 | } |
| 156 | |
| 157 | /// <summary> |
| 158 | /// Gets or sets the conversation information for the Teams conversation. |
| 159 | /// </summary> |
| 160 | [JsonPropertyName("conversation")] |
| 161 | public new TeamsConversation Conversation |
| 162 | { |
| 163 | get => (base.Conversation as TeamsConversation) ?? new TeamsConversation(base.Conversation); |
| 164 | set => base.Conversation = value; |
| 165 | } |
| 166 | |
| 167 | /// <summary> |
| 168 | /// Gets or sets the Teams-specific channel data associated with this activity. |
| 169 | /// </summary> |
| 170 | [JsonPropertyName("channelData")] |
| 171 | public new TeamsChannelData? ChannelData |
| 172 | { |
| 173 | get => base.ChannelData as TeamsChannelData; |
| 174 | set => base.ChannelData = value; |
| 175 | } |
| 176 | |
| 177 | /// <summary> |
| 178 | /// Gets or sets the entities specific to Teams. |
| 179 | /// </summary> |
| 180 | [JsonPropertyName("entities")] public new EntityList? Entities { get; set; } |
| 181 | |
| 182 | /// <summary> |
| 183 | /// Attachments specific to Teams. |
| 184 | /// </summary> |
| 185 | [JsonPropertyName("attachments")] public new IList<TeamsAttachment>? Attachments { get; set; } |
| 186 | |
| 187 | /// <summary> |
| 188 | /// Adds an entity to the activity's Entities collection. |
| 189 | /// </summary> |
| 190 | /// <param name="entity"></param> |
| 191 | /// <returns></returns> |
| 192 | public TeamsActivity AddEntity(Entity entity) |
| 193 | { |
| 194 | // TODO: Pick up nuances about entities. |
| 195 | // For eg, there can only be 1 single MessageEntity |
| 196 | Entities ??= []; |
| 197 | Entities.Add(entity); |
| 198 | return this; |
| 199 | } |
| 200 | |
| 201 | /// <summary> |
| 202 | /// Creates a new TeamsActivityBuilder instance for building a TeamsActivity with a fluent API. |
| 203 | /// </summary> |
| 204 | /// <returns>A new TeamsActivityBuilder instance.</returns> |
| 205 | public static new TeamsActivityBuilder CreateBuilder() => new(); |
| 206 | |
| 207 | /// <summary> |
| 208 | /// Creates a new TeamsActivityBuilder instance initialized with the specified TeamsActivity. |
| 209 | /// </summary> |
| 210 | /// <param name="activity"></param> |
| 211 | /// <returns></returns> |
| 212 | public static TeamsActivityBuilder CreateBuilder(TeamsActivity activity) => new(activity); |
| 213 | |
| 214 | } |
| 215 | |