From 6eda85e651b544d5a64be8eeba8c42a791ff04b1 Mon Sep 17 00:00:00 2001 From: Alex Acebo Date: Tue, 2 Dec 2025 13:19:53 -0800 Subject: [PATCH 1/3] Update Reaction.cs --- .../Microsoft.Teams.Api/Messages/Reaction.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs index 58fe0b35..7a7091ec 100644 --- a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs +++ b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs @@ -15,24 +15,69 @@ namespace Microsoft.Teams.Api.Messages; [JsonConverter(typeof(JsonConverter))] public class ReactionType(string value) : StringEnum(value) { + /// + /// 👍 + /// public static readonly ReactionType Like = new("like"); public bool IsLike => Like.Equals(Value); + /// + /// ❤️ + /// public static readonly ReactionType Heart = new("heart"); public bool IsHeart => Heart.Equals(Value); + /// + /// ✅ + /// + public static readonly ReactionType Checkmark = new("checkmark"); + public bool IsCheckmark => Checkmark.Equals(Value); + + /// + /// ⏳ + /// + public static readonly ReactionType Hourglass = new("hourglass"); + public bool IsHourglass => Hourglass.Equals(Value); + + /// + /// 📌 + /// + public static readonly ReactionType Pushpin = new("pushpin"); + public bool IsPushpin => Pushpin.Equals(Value); + + /// + /// ❗ + /// + public static readonly ReactionType Exclamation = new("exclamation"); + public bool IsExclamation => Exclamation.Equals(Value); + + /// + /// 😆 + /// public static readonly ReactionType Laugh = new("laugh"); public bool IsLaugh => Laugh.Equals(Value); + /// + /// 😮 + /// public static readonly ReactionType Surprise = new("surprise"); public bool IsSurprise => Surprise.Equals(Value); + /// + /// 🙁 + /// public static readonly ReactionType Sad = new("sad"); public bool IsSad => Sad.Equals(Value); + /// + /// 😠 + /// public static readonly ReactionType Angry = new("angry"); public bool IsAngry => Angry.Equals(Value); + /// + /// plus-one + /// public static readonly ReactionType PlusOne = new("plusOne"); public bool IsPlusOne => PlusOne.Equals(Value); } From aa3934354c138db7ca268fe7350d45f68b713c28 Mon Sep 17 00:00:00 2001 From: Alex Acebo Date: Tue, 2 Dec 2025 13:24:27 -0800 Subject: [PATCH 2/3] Update Reaction.cs --- Libraries/Microsoft.Teams.Api/Messages/Reaction.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs index 7a7091ec..ec8613c5 100644 --- a/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs +++ b/Libraries/Microsoft.Teams.Api/Messages/Reaction.cs @@ -9,8 +9,6 @@ namespace Microsoft.Teams.Api.Messages; /// /// The type of reaction given to the -/// message. Possible values include: 'like', 'heart', 'laugh', 'surprised', -/// 'sad', 'angry', 'plusOne' /// [JsonConverter(typeof(JsonConverter))] public class ReactionType(string value) : StringEnum(value) From 2b3288c4499c77fa6be0c3b6556b9f75b4f1e719 Mon Sep 17 00:00:00 2001 From: Alex Acebo Date: Tue, 2 Dec 2025 14:02:21 -0800 Subject: [PATCH 3/3] add client --- .../Clients/ConversationClient.cs | 5 + .../Clients/ReactionClient.cs | 93 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs diff --git a/Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs b/Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs index 8523faae..3ec316aa 100644 --- a/Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs +++ b/Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs @@ -13,12 +13,14 @@ public class ConversationClient : Client public readonly string ServiceUrl; public readonly ActivityClient Activities; public readonly MemberClient Members; + public readonly ReactionClient Reactions; public ConversationClient(string serviceUrl, CancellationToken cancellationToken = default) : base(cancellationToken) { ServiceUrl = serviceUrl; Activities = new ActivityClient(serviceUrl, _http, cancellationToken); Members = new MemberClient(serviceUrl, _http, cancellationToken); + Reactions = new ReactionClient(serviceUrl, _http, cancellationToken); } public ConversationClient(string serviceUrl, IHttpClient client, CancellationToken cancellationToken = default) : base(client, cancellationToken) @@ -26,6 +28,7 @@ public ConversationClient(string serviceUrl, IHttpClient client, CancellationTok ServiceUrl = serviceUrl; Activities = new ActivityClient(serviceUrl, _http, cancellationToken); Members = new MemberClient(serviceUrl, _http, cancellationToken); + Reactions = new ReactionClient(serviceUrl, _http, cancellationToken); } public ConversationClient(string serviceUrl, IHttpClientOptions options, CancellationToken cancellationToken = default) : base(options, cancellationToken) @@ -33,6 +36,7 @@ public ConversationClient(string serviceUrl, IHttpClientOptions options, Cancell ServiceUrl = serviceUrl; Activities = new ActivityClient(serviceUrl, _http, cancellationToken); Members = new MemberClient(serviceUrl, _http, cancellationToken); + Reactions = new ReactionClient(serviceUrl, _http, cancellationToken); } public ConversationClient(string serviceUrl, IHttpClientFactory factory, CancellationToken cancellationToken = default) : base(factory, cancellationToken) @@ -40,6 +44,7 @@ public ConversationClient(string serviceUrl, IHttpClientFactory factory, Cancell ServiceUrl = serviceUrl; Activities = new ActivityClient(serviceUrl, _http, cancellationToken); Members = new MemberClient(serviceUrl, _http, cancellationToken); + Reactions = new ReactionClient(serviceUrl, _http, cancellationToken); } public async Task CreateAsync(CreateRequest request) diff --git a/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs b/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs new file mode 100644 index 00000000..5759d686 --- /dev/null +++ b/Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Microsoft.Teams.Api.Messages; +using Microsoft.Teams.Common.Http; + +namespace Microsoft.Teams.Api.Clients; + +/// +/// Client for working with app message reactions for a given conversation/activity. +/// +public class ReactionClient : Client +{ + public readonly string ServiceUrl; + + public ReactionClient(string serviceUrl, CancellationToken cancellationToken = default) + : base(cancellationToken) + { + ServiceUrl = serviceUrl; + } + + public ReactionClient(string serviceUrl, IHttpClient client, CancellationToken cancellationToken = default) + : base(client, cancellationToken) + { + ServiceUrl = serviceUrl; + } + + public ReactionClient(string serviceUrl, IHttpClientOptions options, CancellationToken cancellationToken = default) + : base(options, cancellationToken) + { + ServiceUrl = serviceUrl; + } + + public ReactionClient(string serviceUrl, IHttpClientFactory factory, CancellationToken cancellationToken = default) + : base(factory, cancellationToken) + { + ServiceUrl = serviceUrl; + } + + /// + /// Creates or updates a reaction on an activity in a conversation. + /// + /// The conversation id. + /// The id of the activity to react to. + /// + /// The reaction type (for example: "like", "heart", "laugh", etc.). + /// + /// + /// Optional id of the user on whose behalf the reaction is added/updated (if supported by the service). + /// + /// + /// A describing the reaction, or null if the service returned an empty body. + /// + public async Task CreateOrUpdateAsync( + string conversationId, + string activityId, + ReactionType reactionType + ) + { + // Assumed route: + // PUT v3/conversations/{conversationId}/activities/{activityId}/reactions + var url = $"{ServiceUrl}v3/conversations/{conversationId}/activities/{activityId}/reactions/{reactionType}"; + var req = HttpRequest.Put(url); + await _http.SendAsync(req, _cancellationToken); + } + + /// + /// Removes a reaction from an activity in a conversation. + /// + /// The conversation id. + /// The id of the activity the reaction is on. + /// + /// The reaction type to remove (for example: "like", "heart", "laugh", etc.). + /// + /// + /// Optional id of the user whose reaction should be removed (if supported by the service). + /// + public async Task DeleteAsync( + string conversationId, + string activityId, + ReactionType reactionType + ) + { + // Assumed route: + // DELETE v3/conversations/{conversationId}/activities/{activityId}/reactions/{reactionType} + var url = + $"{ServiceUrl}v3/conversations/{conversationId}/activities/{activityId}/reactions/{reactionType}"; + + var req = HttpRequest.Delete(url); + + await _http.SendAsync(req, _cancellationToken); + } +}