Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core/src/Microsoft.Teams.Apps.BotBuilder/ActivitySchemaMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Bot.Schema.Teams;
using Microsoft.Teams.Core.Schema;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.Teams.Apps.BotBuilder;

Expand Down Expand Up @@ -69,6 +70,10 @@ public static Microsoft.Bot.Schema.ChannelAccount ToCompatChannelAccount(this Mi
Name = account.Name
};

if (!string.IsNullOrEmpty(account.BotId))
{
channelAccount.Properties.Add("botId", account.BotId);
}

if (account.Properties.TryGetValue("aadObjectId", out object? aadObjectId))
{
Expand Down Expand Up @@ -206,6 +211,11 @@ public static Microsoft.Teams.Core.Schema.ChannelAccount FromCompatChannelAccoun

Microsoft.Teams.Core.Schema.ChannelAccount result = new() { Id = account.Id, Name = account.Name };

if (account.Properties is not null && account.Properties.TryGetValue("botId", out JToken? botId))
{
result.BotId = GetStringValue(botId);
}

if (!string.IsNullOrEmpty(account.AadObjectId))
{
result.Properties["aadObjectId"] = account.AadObjectId;
Expand Down
40 changes: 20 additions & 20 deletions core/src/Microsoft.Teams.Apps.BotBuilder/TeamsApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ private static string GetServiceUrl(ITurnContext turnContext)
?? throw new InvalidOperationException("ServiceUrl is required.");
}

private static AgenticIdentity GetIdentity(ITurnContext turnContext)
private static AgenticIdentity? GetIdentity(ITurnContext turnContext)
{
CoreActivity coreActivity = turnContext.Activity.FromBotFrameworkActivity();
return AgenticIdentity.FromAccount(coreActivity.From) ?? new AgenticIdentity();
return AgenticIdentity.FromAccount(coreActivity.Recipient);
}

#endregion
Expand Down Expand Up @@ -87,7 +87,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

Core.Schema.ChannelAccount result = await client.GetConversationMemberAsync<Core.Schema.ChannelAccount>(
conversationId, userId, serviceUrl, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -121,7 +121,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

IList<Core.Schema.ChannelAccount> members = await client.GetConversationMembersAsync(
conversationId, serviceUrl, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -158,7 +158,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

Core.PagedMembersResult pagedMembers = await client.GetConversationPagedMembersAsync(
conversationId, serviceUrl, pageSize, continuationToken, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -192,7 +192,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

Core.Schema.ChannelAccount result = await client.GetConversationMemberAsync<Core.Schema.ChannelAccount>(
t, userId, serviceUrl, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -220,7 +220,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

IList<Core.Schema.ChannelAccount> members = await client.GetConversationMembersAsync(
t, serviceUrl, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -251,7 +251,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

Core.PagedMembersResult pagedMembers = await client.GetConversationPagedMembersAsync(
t, serviceUrl, pageSize, continuationToken, BotRequestContext.FromAgenticIdentity(identity), null, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -280,7 +280,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)
?? throw new InvalidOperationException("The meetingId can only be null if turnContext is within the scope of a MS Teams Meeting.");

Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

ConversationClient client = GetConversationClient(turnContext);
string url = $"{serviceUrl.ToString().TrimEnd('/')}/v1/meetings/{Uri.EscapeDataString(meetingId)}";
Expand Down Expand Up @@ -319,7 +319,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v1/meetings/{Uri.EscapeDataString(meetingId)}/participants/{Uri.EscapeDataString(participantId)}?tenantId={Uri.EscapeDataString(tenantId)}";

Expand Down Expand Up @@ -353,7 +353,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v1/meetings/{Uri.EscapeDataString(meetingId)}/notification";
string body = JsonConvert.SerializeObject(notification);
Expand Down Expand Up @@ -387,7 +387,7 @@ private static AgenticIdentity GetIdentity(ITurnContext turnContext)
?? throw new InvalidOperationException("This method is only valid within the scope of MS Teams Team.");

Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/teams/{Uri.EscapeDataString(t)}";

Expand Down Expand Up @@ -419,7 +419,7 @@ public static async Task<ConversationList> GetTeamChannelsAsync(
?? throw new InvalidOperationException("This method is only valid within the scope of MS Teams Team.");

Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity identity = GetIdentity(turnContext);
AgenticIdentity? identity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/teams/{Uri.EscapeDataString(t)}/conversations";

Expand Down Expand Up @@ -461,7 +461,7 @@ public static async Task<string> SendMessageToListOfUsersAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/batch/conversation/users/";
SendMessageToUsersRequest request = new()
Expand Down Expand Up @@ -503,7 +503,7 @@ public static async Task<string> SendMessageToListOfChannelsAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);
string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/batch/conversation/channels/";
SendMessageToUsersRequest request = new()
{
Expand Down Expand Up @@ -545,7 +545,7 @@ public static async Task<string> SendMessageToAllUsersInTeamAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);
if (activity is not Activity teamActivity)
throw new ArgumentException("Expected a Bot Framework Activity instance.", nameof(activity));
CoreActivity coreActivity = teamActivity.FromBotFrameworkActivity();
Expand Down Expand Up @@ -588,7 +588,7 @@ public static async Task<string> SendMessageToAllUsersInTenantAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);
if (activity is not Activity tenantActivity)
throw new ArgumentException("Expected a Bot Framework Activity instance.", nameof(activity));
CoreActivity coreActivity = tenantActivity.FromBotFrameworkActivity();
Expand Down Expand Up @@ -684,7 +684,7 @@ await turnContext.Adapter.CreateConversationAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);
string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/batch/conversation/{Uri.EscapeDataString(operationId)}";


Expand Down Expand Up @@ -715,7 +715,7 @@ await turnContext.Adapter.CreateConversationAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/batch/conversation/failedentries/{Uri.EscapeDataString(operationId)}";

Expand Down Expand Up @@ -749,7 +749,7 @@ public static async Task CancelOperationAsync(

ConversationClient client = GetConversationClient(turnContext);
Uri serviceUrl = new(GetServiceUrl(turnContext));
AgenticIdentity agenticIdentity = GetIdentity(turnContext);
AgenticIdentity? agenticIdentity = GetIdentity(turnContext);

string url = $"{serviceUrl.ToString().TrimEnd('/')}/v3/batch/conversation/{Uri.EscapeDataString(operationId)}";

Expand Down
2 changes: 1 addition & 1 deletion core/src/Microsoft.Teams.Core/Http/BotRequestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public record BotRequestContext
/// <param name="activity">The inbound activity, or null.</param>
/// <returns>The context, or null when nothing could be derived.</returns>
public static BotRequestContext? FromInboundActivity(CoreActivity? activity)
=> Build(Schema.AgenticIdentity.FromAccount(activity?.Recipient), NormalizeAppId(activity?.Recipient?.Id));
=> Build(Schema.AgenticIdentity.FromAccount(activity?.Recipient), NormalizeAppId(activity?.Recipient?.BotId));
Comment on lines 55 to +56

/// <summary>
/// Builds context carrying only the supplied agentic identity.
Expand Down
6 changes: 6 additions & 0 deletions core/src/Microsoft.Teams.Core/Schema/ChannelAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ public class ChannelAccount()
[JsonPropertyName("id")]
public string? Id { get; set; }

/// <summary>
/// Gets or sets the bot application ID associated with the account.
/// </summary>
[JsonPropertyName("botId")]
public string? BotId { get; set; }

/// <summary>
/// Gets or sets the display name of the channel account.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions core/src/Microsoft.Teams.Core/Schema/CoreActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,13 @@ protected CoreActivity(CoreActivity activity)
private static ChannelAccount CloneChannelAccount(ChannelAccount source) => new()
{
Id = source.Id,
BotId = source.BotId,
Name = source.Name,
IsTargeted = source.IsTargeted,
AgenticAppId = source.AgenticAppId,
AgenticUserId = source.AgenticUserId,
AgenticAppBlueprintId = source.AgenticAppBlueprintId,
TenantId = source.TenantId,
Properties = new ExtendedPropertiesDictionary(source.Properties)
};
#pragma warning restore ExperimentalTeamsTargeted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Bot.Schema;
using Microsoft.Teams.Core.Schema;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.Teams.Apps.BotBuilder.UnitTests
{
Expand Down Expand Up @@ -311,6 +312,17 @@ public void FromCompatChannelAccount_MapsIdAndName()
Assert.Equal("Alice", result.Name);
}

[Fact]
public void FromCompatChannelAccount_MapsBotId()
{
Microsoft.Bot.Schema.ChannelAccount account = new() { Id = "bot-account-id" };
account.Properties["botId"] = "28:bot-app-id";

Microsoft.Teams.Core.Schema.ChannelAccount result = account.FromCompatChannelAccount();

Assert.Equal("28:bot-app-id", result.BotId);
}

[Fact]
public void FromCompatChannelAccount_MapsAadObjectIdToProperties()
{
Expand Down Expand Up @@ -350,6 +362,17 @@ public void FromCompatChannelAccount_ThrowsOnNull()
Microsoft.Bot.Schema.ChannelAccount? account = null;
Assert.Throws<ArgumentNullException>(() => account!.FromCompatChannelAccount());
}

[Fact]
public void ToCompatChannelAccount_MapsBotId()
{
Microsoft.Teams.Core.Schema.ChannelAccount account = new() { Id = "bot-account-id", BotId = "28:bot-app-id" };

Microsoft.Bot.Schema.ChannelAccount result = account.ToCompatChannelAccount();

Assert.True(result.Properties.TryGetValue("botId", out JToken? botId));
Assert.Equal("28:bot-app-id", botId?.ToString());
}
}

public class FromCompatConversationParametersTests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public void FromInboundActivity_TakesBotAppIdAndAgenticFromRecipient()
{
Type = ActivityType.Message,
From = new ChannelAccount { Id = "user-id" },
Recipient = new ChannelAccount { Id = "28:recipient-bot-id", AgenticUserId = "agentic-user" },
Recipient = new ChannelAccount { Id = "recipient-account-id", BotId = "28:recipient-bot-id", AgenticUserId = "agentic-user" },
};

BotRequestContext? ctx = BotRequestContext.FromInboundActivity(activity);
Expand All @@ -133,7 +133,7 @@ public void FromInboundActivity_IgnoresAgenticFieldsOnSender()
{
Type = ActivityType.Message,
From = new ChannelAccount { Id = "user-id", AgenticUserId = "agentic-user" },
Recipient = new ChannelAccount { Id = "28:recipient-bot-id" },
Recipient = new ChannelAccount { Id = "recipient-account-id", BotId = "28:recipient-bot-id" },
};

BotRequestContext? ctx = BotRequestContext.FromInboundActivity(activity);
Expand Down
Loading