Skip to content
Merged
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
13 changes: 12 additions & 1 deletion Libraries/Microsoft.Teams.Api/Clients/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ public class ApiClient : Client
public virtual TeamClient Teams { get; }
public virtual MeetingClient Meetings { get; }

/// <summary>
/// Gets the underlying <see cref="IHttpClient"/> instance used by this <see cref="ApiClient"/>
/// and its sub-clients to perform HTTP requests.
/// </summary>
/// <remarks>
/// This property is provided for advanced scenarios where you need to issue custom HTTP
/// calls that are not yet covered by the strongly-typed clients exposed by <see cref="ApiClient"/>.
/// Prefer using the typed clients (<see cref="Bots"/>, <see cref="Conversations"/>,
/// <see cref="Users"/>, <see cref="Teams"/>, <see cref="Meetings"/>) whenever possible.
/// Relying on this property may couple your code to the current HTTP implementation and
/// could limit future refactoring of the underlying client.
/// </remarks>
public IHttpClient Client { get => base._http; }

public ApiClient(string serviceUrl, CancellationToken cancellationToken = default) : base(cancellationToken)
Expand All @@ -34,7 +46,6 @@ public ApiClient(string serviceUrl, IHttpClient client, CancellationToken cancel
Users = new UserClient(_http, cancellationToken);
Teams = new TeamClient(serviceUrl, _http, cancellationToken);
Meetings = new MeetingClient(serviceUrl, _http, cancellationToken);

}

public ApiClient(string serviceUrl, IHttpClientOptions options, CancellationToken cancellationToken = default) : base(options, cancellationToken)
Expand Down
13 changes: 5 additions & 8 deletions Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Teams.Api.Messages;
Expand Down Expand Up @@ -45,11 +45,8 @@ public ReactionClient(string serviceUrl, IHttpClientFactory factory, Cancellatio
/// <param name="reactionType">
/// The reaction type (for example: "like", "heart", "laugh", etc.).
/// </param>
/// <param name="userId">
/// Optional id of the user on whose behalf the reaction is added/updated (if supported by the service).
/// </param>
/// <returns>
/// A <see cref="Resource"/> describing the reaction, or <c>null</c> if the service returned an empty body.
/// A <see cref="Task"/> representing the asynchronous operation.
/// </returns>
public async Task CreateOrUpdateAsync(
string conversationId,
Expand All @@ -72,9 +69,9 @@ ReactionType reactionType
/// <param name="reactionType">
/// The reaction type to remove (for example: "like", "heart", "laugh", etc.).
/// </param>
/// <param name="userId">
/// Optional id of the user whose reaction should be removed (if supported by the service).
/// </param>
/// <returns>
/// A <see cref="Task"/> representing the asynchronous operation.
/// </returns>
public async Task DeleteAsync(
string conversationId,
string activityId,
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Microsoft.Teams.Api/Messages/Reaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Microsoft.Teams.Api.Messages;

/// <summary>
/// The type of reaction given to the
/// The type of reaction given to the message.
/// </summary>
[JsonConverter(typeof(JsonConverter<ReactionType>))]
public class ReactionType(string value) : StringEnum(value)
Expand Down
2 changes: 1 addition & 1 deletion Samples/Samples.Reactions/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
teams.OnMessageReaction(async (context, cancellationToken) =>
{
context.Log.Info($"Reaction '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' added by {context.Activity.From?.Name}");
await context.Send($"you reacted with added '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' " +
await context.Send($"you added '{context.Activity.ReactionsAdded?.FirstOrDefault()?.Type}' " +
$"and removed '{context.Activity.ReactionsRemoved?.FirstOrDefault()?.Type}'", cancellationToken);
});

Expand Down
74 changes: 74 additions & 0 deletions Tests/Microsoft.Teams.Api.Tests/Clients/ReactionClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.Net;

using Microsoft.Teams.Api.Clients;
using Microsoft.Teams.Api.Messages;
using Microsoft.Teams.Common.Http;

using Moq;

namespace Microsoft.Teams.Api.Tests.Clients;

public class ReactionClientTests
{
[Fact]
public async Task ReactionClient_CreateOrUpdateAsync()
{
var responseMessage = new HttpResponseMessage();
responseMessage.Headers.Add("Custom-Header", "HeaderValue");
var mockHandler = new Mock<IHttpClient>();
mockHandler
.Setup(handler => handler.SendAsync(It.IsAny<IHttpRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new HttpResponse<string>()
{
Headers = responseMessage.Headers,
StatusCode = HttpStatusCode.OK,
Body = string.Empty
});

string serviceUrl = "https://serviceurl.com/";
var reactionClient = new ReactionClient(serviceUrl, mockHandler.Object);
string conversationId = "conversationId";
string activityId = "activityId";
var reactionType = ReactionType.Like;

await reactionClient.CreateOrUpdateAsync(conversationId, activityId, reactionType);

string expectedUrl = "https://serviceurl.com/v3/conversations/conversationId/activities/activityId/reactions/like";
HttpMethod expectedMethod = HttpMethod.Put;
mockHandler.Verify(x => x.SendAsync(
It.Is<IHttpRequest>(arg => arg.Url == expectedUrl && arg.Method == expectedMethod),
It.IsAny<CancellationToken>()),
Times.Once);
}

[Fact]
public async Task ReactionClient_DeleteAsync()
{
var responseMessage = new HttpResponseMessage();
responseMessage.Headers.Add("Custom-Header", "HeaderValue");
var mockHandler = new Mock<IHttpClient>();
mockHandler
.Setup(handler => handler.SendAsync(It.IsAny<IHttpRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new HttpResponse<string>()
{
Headers = responseMessage.Headers,
StatusCode = HttpStatusCode.OK,
Body = string.Empty
});

string serviceUrl = "https://serviceurl.com/";
var reactionClient = new ReactionClient(serviceUrl, mockHandler.Object);
string conversationId = "conversationId";
string activityId = "activityId";
var reactionType = ReactionType.Heart;

await reactionClient.DeleteAsync(conversationId, activityId, reactionType);

string expectedUrl = "https://serviceurl.com/v3/conversations/conversationId/activities/activityId/reactions/heart";
HttpMethod expectedMethod = HttpMethod.Delete;
mockHandler.Verify(x => x.SendAsync(
It.Is<IHttpRequest>(arg => arg.Url == expectedUrl && arg.Method == expectedMethod),
It.IsAny<CancellationToken>()),
Times.Once);
}
}