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/TeamsActivityBuilder.cs

216lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.Teams.Bot.Core.Schema;
5
6namespace Microsoft.Teams.Bot.Apps.Schema;
7
8/// <summary>
9/// Provides a fluent API for building TeamsActivity instances.
10/// </summary>
11public class TeamsActivityBuilder : CoreActivityBuilder<TeamsActivity, TeamsActivityBuilder>
12{
13 /// <summary>
14 /// Initializes a new instance of the TeamsActivityBuilder class.
15 /// </summary>
16 internal TeamsActivityBuilder() : base(TeamsActivity.FromActivity(new CoreActivity()))
17 {
18 }
19
20 /// <summary>
21 /// Initializes a new instance of the TeamsActivityBuilder class with an existing activity.
22 /// </summary>
23 /// <param name="activity">The activity to build upon.</param>
24 internal TeamsActivityBuilder(TeamsActivity activity) : base(activity)
25 {
26 }
27
28 /// <summary>
29 /// Sets the conversation (override for Teams-specific type).
30 /// </summary>
31 protected override void SetConversation(Conversation? conversation)
32 {
33 _activity.Conversation = conversation is TeamsConversation teamsConv
34 ? teamsConv
35 : TeamsConversation.FromConversation(conversation);
36 }
37
38 /// <summary>
39 /// Sets the From account (override for Teams-specific type).
40 /// </summary>
41 protected override void SetFrom(ConversationAccount? from)
42 {
43 _activity.From = from is TeamsConversationAccount teamsAccount
44 ? teamsAccount
45 : TeamsConversationAccount.FromConversationAccount(from);
46 }
47
48 /// <summary>
49 /// Sets the Recipient account (override for Teams-specific type).
50 /// </summary>
51 protected override void SetRecipient(ConversationAccount? recipient)
52 {
53 _activity.Recipient = recipient is TeamsConversationAccount teamsAccount
54 ? teamsAccount
55 : TeamsConversationAccount.FromConversationAccount(recipient);
56 }
57
58 /// <summary>
59 /// Sets the Teams-specific channel data.
60 /// </summary>
61 /// <param name="channelData">The channel data.</param>
62 /// <returns>The builder instance for chaining.</returns>
63 public TeamsActivityBuilder WithChannelData(TeamsChannelData? channelData)
64 {
65 _activity.ChannelData = channelData;
66 return this;
67 }
68
69 /// <summary>
70 /// Sets the entities collection.
71 /// </summary>
72 /// <param name="entities">The entities collection.</param>
73 /// <returns>The builder instance for chaining.</returns>
74 public TeamsActivityBuilder WithEntities(EntityList entities)
75 {
76 _activity.Entities = entities;
77 return this;
78 }
79
80 /// <summary>
81 /// Sets the attachments collection.
82 /// </summary>
83 /// <param name="attachments">The attachments collection.</param>
84 /// <returns>The builder instance for chaining.</returns>
85 public TeamsActivityBuilder WithAttachments(IList<TeamsAttachment> attachments)
86 {
87 _activity.Attachments = attachments;
88 return this;
89 }
90
91 // TODO: Builders should only have "With" methods, not "Add" methods.
92 /// <summary>
93 /// Replaces the attachments collection with a single attachment.
94 /// </summary>
95 /// <param name="attachment">The attachment to set. Passing null clears the attachments.</param>
96 /// <returns>The builder instance for chaining.</returns>
97 public TeamsActivityBuilder WithAttachment(TeamsAttachment? attachment)
98 {
99 _activity.Attachments = attachment is null
100 ? null
101 : [attachment];
102
103 return this;
104 }
105
106 /// <summary>
107 /// Adds an entity to the activity's Entities collection.
108 /// </summary>
109 /// <param name="entity">The entity to add.</param>
110 /// <returns>The builder instance for chaining.</returns>
111 public TeamsActivityBuilder AddEntity(Entity entity)
112 {
113 _activity.Entities ??= [];
114 _activity.Entities.Add(entity);
115 return this;
116 }
117
118 /// <summary>
119 /// Adds an attachment to the activity's Attachments collection.
120 /// </summary>
121 /// <param name="attachment">The attachment to add.</param>
122 /// <returns>The builder instance for chaining.</returns>
123 public TeamsActivityBuilder AddAttachment(TeamsAttachment attachment)
124 {
125 _activity.Attachments ??= [];
126 _activity.Attachments.Add(attachment);
127 return this;
128 }
129
130 /// <summary>
131 /// Adds an Adaptive Card attachment to the activity.
132 /// </summary>
133 /// <param name="adaptiveCard">The Adaptive Card payload.</param>
134 /// <param name="configure">Optional callback to further configure the attachment before it is added.</param>
135 /// <returns>The builder instance for chaining.</returns>
136 public TeamsActivityBuilder AddAdaptiveCardAttachment(object adaptiveCard, Action<TeamsAttachmentBuilder>? configure = null)
137 {
138 TeamsAttachment attachment = BuildAdaptiveCardAttachment(adaptiveCard, configure);
139 return AddAttachment(attachment);
140 }
141
142 /// <summary>
143 /// Sets the activity attachments collection to a single Adaptive Card attachment.
144 /// </summary>
145 /// <param name="adaptiveCard">The Adaptive Card payload.</param>
146 /// <param name="configure">Optional callback to further configure the attachment.</param>
147 /// <returns>The builder instance for chaining.</returns>
148 public TeamsActivityBuilder WithAdaptiveCardAttachment(object adaptiveCard, Action<TeamsAttachmentBuilder>? configure = null)
149 {
150 TeamsAttachment attachment = BuildAdaptiveCardAttachment(adaptiveCard, configure);
151 return WithAttachment(attachment);
152 }
153
154 /// <summary>
155 /// Adds or sets the text content of the activity.
156 /// </summary>
157 /// <param name="text"></param>
158 /// <param name="textFormat"></param>
159 /// <returns></returns>
160 public TeamsActivityBuilder WithText(string text, string textFormat = "plain")
161 {
162 WithProperty("text", text);
163 WithProperty("textFormat", textFormat);
164 return this;
165 }
166
167 /// <summary>
168 /// Adds a mention to the activity.
169 /// </summary>
170 /// <param name="account">The account to mention.</param>
171 /// <param name="text">Optional custom text for the mention. If null, uses the account name.</param>
172 /// <param name="addText">Whether to prepend the mention text to the activity's text content.</param>
173 /// <returns>The builder instance for chaining.</returns>
174 public TeamsActivityBuilder AddMention(ConversationAccount account, string? text = null, bool addText = true)
175 {
176 ArgumentNullException.ThrowIfNull(account);
177 string? mentionText = text ?? account.Name;
178
179 if (addText)
180 {
181 string? currentText = _activity.Properties.TryGetValue("text", out object? value) ? value?.ToString() : null;
182 WithProperty("text", $"<at>{mentionText}</at> {currentText}");
183 }
184
185 _activity.Entities ??= [];
186 _activity.Entities.Add(new MentionEntity(account, $"<at>{mentionText}</at>"));
187
188 CoreActivity baseActivity = _activity;
189 baseActivity.Entities = _activity.Entities.ToJsonArray();
190
191 return this;
192 }
193
194 /// <summary>
195 /// Builds and returns the configured TeamsActivity instance.
196 /// </summary>
197 /// <returns>The configured TeamsActivity.</returns>
198 public override TeamsActivity Build()
199 {
200 _activity.Rebase();
201 return _activity;
202 }
203
204 private static TeamsAttachment BuildAdaptiveCardAttachment(object adaptiveCard, Action<TeamsAttachmentBuilder>? configure)
205 {
206 ArgumentNullException.ThrowIfNull(adaptiveCard);
207
208 TeamsAttachmentBuilder attachmentBuilder = TeamsAttachment
209 .CreateBuilder()
210 .WithAdaptiveCard(adaptiveCard);
211
212 configure?.Invoke(attachmentBuilder);
213
214 return attachmentBuilder.Build();
215 }
216}
217