From f56cb020f6a73547d72c5bdc47e8c8457e137a8e Mon Sep 17 00:00:00 2001 From: John Johansson <1345217+we4sz@users.noreply.github.com> Date: Sat, 31 Oct 2026 08:52:37 +0100 Subject: [PATCH 1/2] Adding ContextTeamId, Updated and IsOpen to Conversation --- SlackNet.Tests/Objects/ConversationTests.cs | 38 +++++++++++++++++++++ SlackNet/Objects/Conversation.cs | 15 ++++++++ 2 files changed, 53 insertions(+) create mode 100644 SlackNet.Tests/Objects/ConversationTests.cs diff --git a/SlackNet.Tests/Objects/ConversationTests.cs b/SlackNet.Tests/Objects/ConversationTests.cs new file mode 100644 index 00000000..11f5cfe5 --- /dev/null +++ b/SlackNet.Tests/Objects/ConversationTests.cs @@ -0,0 +1,38 @@ +using EasyAssertions; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace SlackNet.Tests.Objects; + +public class ConversationTests +{ + private JsonSerializerSettings _sut; + + [SetUp] + public void SetUp() + { + _sut = Default.JsonSettings(Default.SlackTypeResolver(Default.AssembliesContainingSlackTypes)).SerializerSettings; + } + + [Test] + public void Conversation_DirectMessage_HasContextTeamIdUpdatedAndIsOpen() + { + var result = Deserialize(@"{ ""id"": ""D12345678"", ""created"": 1788600021, ""updated"": 1788600021450, ""is_im"": true, ""is_open"": true, ""context_team_id"": ""T12345678"", ""user"": ""U12345678"" }"); + + result.ContextTeamId.ShouldBe("T12345678"); + result.Updated.ShouldBe(1788600021450); + result.IsOpen.ShouldBe(true); + } + + [Test] + public void Conversation_WithoutThoseFields_HasDefaults() + { + var result = Deserialize(@"{ ""id"": ""C12345678"", ""is_channel"": true }"); + + result.ContextTeamId.ShouldBeNull(); + result.Updated.ShouldBe(0L); + result.IsOpen.ShouldBe(false); + } + + private T Deserialize(string json) => JsonConvert.DeserializeObject(json, _sut); +} diff --git a/SlackNet/Objects/Conversation.cs b/SlackNet/Objects/Conversation.cs index 8c826bfd..53dd5e4e 100644 --- a/SlackNet/Objects/Conversation.cs +++ b/SlackNet/Objects/Conversation.cs @@ -39,6 +39,11 @@ public class Conversation [JsonIgnore] public DateTime CreatedDate => Created.ToDateTime().GetValueOrDefault(); + /// + /// The timestamp, in milliseconds (not seconds like ), when the channel settings were updated - for example, the "topic" or "description" of the channel changed. + /// + public long Updated { get; set; } + /// /// The user ID of the member that created this channel. /// @@ -49,6 +54,11 @@ public class Conversation /// public string ConversationHostId { get; set; } + /// + /// The ID of the workspace the conversation is within. + /// + public string ContextTeamId { get; set; } + /// /// Indicates a conversation is archived. Frozen in time. /// @@ -106,6 +116,11 @@ public class Conversation /// public bool IsMpim { get; set; } + /// + /// Whether a DM is open; this field is DM/MPIM-specific. + /// + public bool IsOpen { get; set; } + /// /// The timestamp for the last message the calling user has read in this channel. /// From 13559d2a9a5909fe5299af58a2516a7dc735e3e7 Mon Sep 17 00:00:00 2001 From: John Johansson <1345217+we4sz@users.noreply.github.com> Date: Sat, 31 Oct 2026 09:43:05 +0100 Subject: [PATCH 2/2] Adding IsFrozen, SharedTeamIds, InternalTeamIds, ConnectedTeamIds and PendingConnectedTeamIds to Conversation --- SlackNet.Tests/Objects/ConversationTests.cs | 24 ++++++++++++++++++++ SlackNet/Objects/Conversation.cs | 25 +++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/SlackNet.Tests/Objects/ConversationTests.cs b/SlackNet.Tests/Objects/ConversationTests.cs index 11f5cfe5..f0810eff 100644 --- a/SlackNet.Tests/Objects/ConversationTests.cs +++ b/SlackNet.Tests/Objects/ConversationTests.cs @@ -34,5 +34,29 @@ public void Conversation_WithoutThoseFields_HasDefaults() result.IsOpen.ShouldBe(false); } + [Test] + public void Conversation_SharedChannel_HasFrozenStateAndTeamIds() + { + var result = Deserialize(@"{ ""id"": ""C12345678"", ""is_ext_shared"": true, ""is_frozen"": true, ""shared_team_ids"": [""T111"", ""T222""], ""internal_team_ids"": [""T111""], ""connected_team_ids"": [""T333""], ""pending_connected_team_ids"": [""T444""] }"); + + result.IsFrozen.ShouldBe(true); + result.SharedTeamIds.ShouldMatch(["T111", "T222"]); + result.InternalTeamIds.ShouldMatch(["T111"]); + result.ConnectedTeamIds.ShouldMatch(["T333"]); + result.PendingConnectedTeamIds.ShouldMatch(["T444"]); + } + + [Test] + public void Conversation_NotShared_HasNoTeamIds() + { + var result = Deserialize(@"{ ""id"": ""C12345678"", ""is_channel"": true }"); + + result.IsFrozen.ShouldBe(false); + result.SharedTeamIds.ShouldBeEmpty(); + result.InternalTeamIds.ShouldBeEmpty(); + result.ConnectedTeamIds.ShouldBeEmpty(); + result.PendingConnectedTeamIds.ShouldBeEmpty(); + } + private T Deserialize(string json) => JsonConvert.DeserializeObject(json, _sut); } diff --git a/SlackNet/Objects/Conversation.cs b/SlackNet/Objects/Conversation.cs index 53dd5e4e..7b4b2532 100644 --- a/SlackNet/Objects/Conversation.cs +++ b/SlackNet/Objects/Conversation.cs @@ -64,6 +64,11 @@ public class Conversation /// public bool IsArchived { get; set; } + /// + /// Whether the conversation is frozen (e.g. a disconnected Slack Connect channel becomes a read-only frozen copy on the away-team side). + /// + public bool IsFrozen { get; set; } + /// /// Means the channel is the workspace's "general" discussion channel (even if it's not named #general but it might be anyway). /// That might be important to your app because almost every user is a member. @@ -95,6 +100,26 @@ public class Conversation public object[] PendingShared { get; set; } + /// + /// IDs of workspaces the channel is shared with. + /// + public IList SharedTeamIds { get; set; } = []; + + /// + /// Internal team IDs for shared channels. + /// + public IList InternalTeamIds { get; set; } = []; + + /// + /// Connected external team IDs. + /// + public IList ConnectedTeamIds { get; set; } = []; + + /// + /// Pending connected team IDs. + /// + public IList PendingConnectedTeamIds { get; set; } = []; + /// /// Is intriguing. It means the conversation is ready to become an channel but isn't quite ready yet /// and needs some kind of approval or sign off. Best to treat it as if it were a shared channel, even if it traverses only one workspace.