diff --git a/SlackNet.Tests/ExtraPropertiesTests.cs b/SlackNet.Tests/ExtraPropertiesTests.cs new file mode 100644 index 00000000..fe469a11 --- /dev/null +++ b/SlackNet.Tests/ExtraPropertiesTests.cs @@ -0,0 +1,110 @@ +using System.Linq; +using System.Threading.Tasks; +using EasyAssertions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using SlackNet.Blocks; +using SlackNet.Events; + +namespace SlackNet.Tests; + +public class ExtraPropertiesTests +{ + private TestHttp _http; + private ISlackApiClient _api; + private JsonSerializerSettings _sut; + + [SetUp] + public void SetUp() + { + var jsonSettings = Default.JsonSettings(Default.SlackTypeResolver(Default.AssembliesContainingSlackTypes)); + _sut = jsonSettings.SerializerSettings; + _http = new TestHttp(); + _api = new SlackApiClient(_http, Default.UrlBuilder(jsonSettings), jsonSettings, "token"); + } + + [Test] + public async Task User_PropertiesSlackNetDoesNotKnowAbout_AreInExtraProperties() + { + _http.Response = JObject.Parse(@"{ + ""ok"": true, + ""user"": { + ""id"": ""U12345678"", + ""a_flag_slack_adds_later"": true, + ""profile"": { ""email"": ""ada@example.com"", ""a_string_slack_adds_later"": ""foo"" }, + ""enterprise_user"": { ""id"": ""W12345678"", ""a_number_slack_adds_later"": 42 } + } + }"); + + var user = await _api.Users.Info("U12345678"); + + user.Id.ShouldBe("U12345678"); + user.ExtraProperties["a_flag_slack_adds_later"].ShouldBe(true); + user.Profile.Email.ShouldBe("ada@example.com"); + user.Profile.ExtraProperties["a_string_slack_adds_later"].ShouldBe("foo"); + user.EnterpriseUser.ExtraProperties["a_number_slack_adds_later"].ShouldBe(42L); + } + + [Test] + public async Task User_WithOnlyPropertiesSlackNetKnows_HasNoExtraProperties() + { + _http.Response = JObject.Parse(@"{ ""ok"": true, ""user"": { ""id"": ""U12345678"", ""is_admin"": true, ""profile"": { ""email"": ""ada@example.com"" } } }"); + + var user = await _api.Users.Info("U12345678"); + + user.ExtraProperties.ShouldBeEmpty(); + user.Profile.ExtraProperties.ShouldBeEmpty(); + } + + [Test] + public async Task Conversation_PropertiesSlackNetDoesNotKnowAbout_AreInExtraProperties() + { + _http.Response = JObject.Parse(@"{ + ""ok"": true, + ""channel"": { + ""id"": ""C12345678"", + ""a_flag_slack_adds_later"": true, + ""topic"": { ""value"": ""Hello"", ""a_string_slack_adds_later"": ""foo"" } + } + }"); + + var conversation = await _api.Conversations.Info("C12345678"); + + conversation.ExtraProperties["a_flag_slack_adds_later"].ShouldBe(true); + conversation.Topic.ExtraProperties["a_string_slack_adds_later"].ShouldBe("foo"); + } + + [Test] + public void Block_PropertiesSlackNetDoesNotKnowAbout_AreInExtraProperties() + { + var result = Deserialize(@"{ + ""type"": ""message"", + ""blocks"": [ + { + ""type"": ""section"", + ""text"": { ""type"": ""mrkdwn"", ""text"": ""Hello"", ""a_flag_slack_adds_later"": true }, + ""a_string_slack_adds_later"": ""foo"" + } + ] + }"); + + var section = result.ShouldBeA().And.Blocks.Single().ShouldBeA().And; + section.ExtraProperties["a_string_slack_adds_later"].ShouldBe("foo"); + section.Text.ExtraProperties["a_flag_slack_adds_later"].ShouldBe(true); + } + + [Test] + public void ExtraProperties_AreNotSentBackToSlack() + { + var block = Deserialize(@"{ ""type"": ""section"", ""text"": { ""type"": ""plain_text"", ""text"": ""Hello"" }, ""a_string_slack_adds_later"": ""foo"" }"); + block.ExtraProperties.Keys.ShouldContain("a_string_slack_adds_later"); + + var json = JObject.Parse(JsonConvert.SerializeObject(block, _sut)); + + json.Value("type").ShouldBe("section"); + json.ContainsKey("a_string_slack_adds_later").ShouldBe(false); + } + + private T Deserialize(string json) => JsonConvert.DeserializeObject(json, _sut); +} diff --git a/SlackNet.Tests/ModelLintTests.cs b/SlackNet.Tests/ModelLintTests.cs new file mode 100644 index 00000000..54ee1221 --- /dev/null +++ b/SlackNet.Tests/ModelLintTests.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using EasyAssertions; +using Newtonsoft.Json; +using NUnit.Framework; +using SlackNet.Events; +using SlackNet.SocketMode; +using SlackNet.WebApi; + +namespace SlackNet.Tests; + +public class ModelLintTests +{ + [Test] + public void AllModelsHaveACatchAllForUnknownProperties() + { + ModelTypes + .Where(t => !t.IsAssignableTo(typeof(SlackObject)) && !WithTheirOwnCatchAll.Any(t.IsAssignableTo)) + .ShouldBeEmpty("Models should derive from SlackObject, so that nothing Slack adds to them is lost"); + } + + [Test] + public void UnknownPropertiesAreReadButNotWritten() + { + var settings = Default.JsonSettings().SerializerSettings; + + ModelTypes + .Where(t => t.IsAssignableTo(typeof(SlackObject))) + .Where(t => + { + var model = (SlackObject)JsonConvert.DeserializeObject(@"{ ""not_modelled_yet"": ""value"" }", t, settings); + return model?.ExtraProperties.ContainsKey("not_modelled_yet") != true + || JsonConvert.SerializeObject(model, settings).Contains("not_modelled_yet"); + }) + .ShouldBeEmpty("Unknown properties should end up in ExtraProperties, and not be written back when the model is sent to Slack"); + } + + // Everything Json.NET can fill in from a JSON object + private static IEnumerable ModelTypes => typeof(SlackObject).Assembly + .GetExportedTypes() + .Where(t => t is { IsClass: true, IsAbstract: false, IsGenericTypeDefinition: false } + && t.GetConstructor(Type.EmptyTypes) != null + && t.GetProperties(BindingFlags.Public | BindingFlags.Instance).Any(p => p.SetMethod?.IsPublic == true && p.GetIndexParameters().Length == 0)) + .Except(NotModels); + + private static readonly Type[] NotModels = + [ + typeof(SlackRequestContext), // Local context for the request being handled + typeof(SocketModeConnectionOptions), // Local configuration + ]; + + // These have extension data of their own, which Json.NET fills instead of the one on SlackObject, so they don't derive from it + private static readonly Type[] WithTheirOwnCatchAll = + [ + typeof(Event), // Also written back, which it always has been + typeof(MessageSearchResult), // Same as Event + typeof(Icons), // Images are what's left over after the known properties + typeof(ErrorResponse), // Info is what's left over after the known properties + typeof(WebApiResponse), // Data is the whole response + ]; +} diff --git a/SlackNet/Blocks/Block.cs b/SlackNet/Blocks/Block.cs index 329d372c..da48c24b 100644 --- a/SlackNet/Blocks/Block.cs +++ b/SlackNet/Blocks/Block.cs @@ -1,6 +1,6 @@ namespace SlackNet.Blocks; -public abstract class Block(string type) +public abstract class Block(string type) : SlackObject { public string Type { get; } = type; diff --git a/SlackNet/Blocks/BlockAction.cs b/SlackNet/Blocks/BlockAction.cs index 13dceef6..5970bae1 100644 --- a/SlackNet/Blocks/BlockAction.cs +++ b/SlackNet/Blocks/BlockAction.cs @@ -3,7 +3,7 @@ namespace SlackNet.Blocks; -public class BlockAction +public class BlockAction : SlackObject { public string Type { get; set; } public string ActionId { get; set; } diff --git a/SlackNet/Blocks/BlockElement.cs b/SlackNet/Blocks/BlockElement.cs index 16d11bd9..957efa31 100644 --- a/SlackNet/Blocks/BlockElement.cs +++ b/SlackNet/Blocks/BlockElement.cs @@ -5,7 +5,7 @@ public interface IBlockElement string Type { get; } } -public abstract class BlockElement(string type) : IBlockElement +public abstract class BlockElement(string type) : SlackObject, IBlockElement { public string Type { get; } = type; } \ No newline at end of file diff --git a/SlackNet/Blocks/ConfirmationDialog.cs b/SlackNet/Blocks/ConfirmationDialog.cs index 0fb84afa..96ed4ad6 100644 --- a/SlackNet/Blocks/ConfirmationDialog.cs +++ b/SlackNet/Blocks/ConfirmationDialog.cs @@ -4,7 +4,7 @@ /// An object that defines a dialog that provides a confirmation step to any interactive element. /// This dialog will ask the user to confirm their action by offering a confirm and deny buttons. /// -public class ConfirmationDialog +public class ConfirmationDialog : SlackObject { /// /// A plain text object that defines the dialog's title. diff --git a/SlackNet/Blocks/ContextActionsBlock.cs b/SlackNet/Blocks/ContextActionsBlock.cs index 117440d1..33bd386e 100644 --- a/SlackNet/Blocks/ContextActionsBlock.cs +++ b/SlackNet/Blocks/ContextActionsBlock.cs @@ -8,7 +8,7 @@ public class ContextActionsBlock() : Block("context_actions") public IList Elements { get; set; } = []; } -public abstract class ContextActionsElement(string type) +public abstract class ContextActionsElement(string type) : SlackObject { public string Type { get; set; } = type; public string ActionId { get; set; } diff --git a/SlackNet/Blocks/ConversationFilter.cs b/SlackNet/Blocks/ConversationFilter.cs index c03ea173..89ef873d 100644 --- a/SlackNet/Blocks/ConversationFilter.cs +++ b/SlackNet/Blocks/ConversationFilter.cs @@ -5,7 +5,7 @@ namespace SlackNet.Blocks; /// /// Provides a way to filter the list of options in a or . /// -public class ConversationFilter +public class ConversationFilter : SlackObject { /// /// Indicates which type of conversations should be included in the list. diff --git a/SlackNet/Blocks/DataVisualizationBlock.cs b/SlackNet/Blocks/DataVisualizationBlock.cs index 1f88c2e3..5d2d0906 100644 --- a/SlackNet/Blocks/DataVisualizationBlock.cs +++ b/SlackNet/Blocks/DataVisualizationBlock.cs @@ -23,7 +23,7 @@ public class DataVisualizationBlock() : Block("data_visualization") /// /// A chart displayed by a . /// -public abstract class DataVisualizationChart(string type) +public abstract class DataVisualizationChart(string type) : SlackObject { /// /// The type of chart. @@ -80,7 +80,7 @@ public class LineChart() : AxisChart("line"); /// /// A labeled slice in a . /// -public class ChartSegment +public class ChartSegment : SlackObject { /// /// Display name for this slice, shown in the legend and on hover. @@ -96,7 +96,7 @@ public class ChartSegment /// /// A named set of ordered data points. /// -public class DataSeries +public class DataSeries : SlackObject { /// /// Human-readable identifier displayed in the chart legend. @@ -112,7 +112,7 @@ public class DataSeries /// /// A value belonging to an x-axis category. /// -public class DataPoint +public class DataPoint : SlackObject { /// /// The x-axis category this point belongs to. @@ -128,7 +128,7 @@ public class DataPoint /// /// X-axis categories and optional axis titles. /// -public class AxisConfig +public class AxisConfig : SlackObject { /// /// Category labels for the x-axis, in display order. diff --git a/SlackNet/Blocks/DispatchActionConfig.cs b/SlackNet/Blocks/DispatchActionConfig.cs index 1d70e936..4644c569 100644 --- a/SlackNet/Blocks/DispatchActionConfig.cs +++ b/SlackNet/Blocks/DispatchActionConfig.cs @@ -5,7 +5,7 @@ namespace SlackNet.Blocks; /// /// Determines when a element will return a interaction payload. /// -public class DispatchActionConfig +public class DispatchActionConfig : SlackObject { /// /// An array of that you would like to receive a payload for. diff --git a/SlackNet/Blocks/FeedbackButtons.cs b/SlackNet/Blocks/FeedbackButtons.cs index 983aeb94..e1ce3252 100644 --- a/SlackNet/Blocks/FeedbackButtons.cs +++ b/SlackNet/Blocks/FeedbackButtons.cs @@ -7,7 +7,7 @@ public class FeedbackButtons() : ContextActionsElement("feedback_buttons") public FeedbackButton NegativeButton { get; set; } = new(); } -public class FeedbackButton +public class FeedbackButton : SlackObject { public PlainText Text { get; set; } public string Value { get; set; } diff --git a/SlackNet/Blocks/ImageFileReference.cs b/SlackNet/Blocks/ImageFileReference.cs index 7462b552..11e87190 100644 --- a/SlackNet/Blocks/ImageFileReference.cs +++ b/SlackNet/Blocks/ImageFileReference.cs @@ -3,7 +3,7 @@ /// /// Defines an object containing Slack file information to be used in an image block or image element. /// -public class ImageFileReference +public class ImageFileReference : SlackObject { /// /// This URL can be the or the of the Slack . diff --git a/SlackNet/Blocks/Option.cs b/SlackNet/Blocks/Option.cs index ebc83f7b..17d55f8c 100644 --- a/SlackNet/Blocks/Option.cs +++ b/SlackNet/Blocks/Option.cs @@ -3,7 +3,7 @@ /// /// An object that represents a single selectable item in a select menu. /// -public class Option +public class Option : SlackObject { /// /// A plain text object that defines the text shown in the option on the menu. diff --git a/SlackNet/Blocks/OptionGroup.cs b/SlackNet/Blocks/OptionGroup.cs index c1c09153..c7eaded2 100644 --- a/SlackNet/Blocks/OptionGroup.cs +++ b/SlackNet/Blocks/OptionGroup.cs @@ -5,7 +5,7 @@ namespace SlackNet.Blocks; /// /// Provides a way to group options in a select menu. /// -public class OptionGroup +public class OptionGroup : SlackObject { /// /// A plain text object that defines the label shown above this group of options. diff --git a/SlackNet/Blocks/RichTextBlock.cs b/SlackNet/Blocks/RichTextBlock.cs index 2292e881..ce4fe33e 100644 --- a/SlackNet/Blocks/RichTextBlock.cs +++ b/SlackNet/Blocks/RichTextBlock.cs @@ -18,7 +18,7 @@ public class RichTextBlock() : Block("rich_text") public IList Elements { get; set; } = []; } -public abstract class RichTextElement(string type) +public abstract class RichTextElement(string type) : SlackObject { public string Type { get; set; } = type; } @@ -32,7 +32,7 @@ public class RichTextSection() : RichTextElement("rich_text_section") public IList Elements { get; set; } = []; } -public abstract class RichTextSectionElement(string type) +public abstract class RichTextSectionElement(string type) : SlackObject { public string Type { get; set; } = type; } @@ -288,7 +288,7 @@ public class RichTextListRecord() : RichTextElement("list_record") /// /// Rich text styling. Note that not all properties are supported by all elements. /// -public class RichTextStyle +public class RichTextStyle : SlackObject { [IgnoreIfDefault] public bool Bold { get; set; } diff --git a/SlackNet/Blocks/SlackIcon.cs b/SlackNet/Blocks/SlackIcon.cs index 0f6a4b35..b1639e45 100644 --- a/SlackNet/Blocks/SlackIcon.cs +++ b/SlackNet/Blocks/SlackIcon.cs @@ -6,7 +6,7 @@ namespace SlackNet.Blocks; /// Defines Slack icon information for use in a . /// /// See the Slack documentation for more information. -public class SlackIcon +public class SlackIcon : SlackObject { /// /// The type of composition object. Always icon. diff --git a/SlackNet/Blocks/TableBlock.cs b/SlackNet/Blocks/TableBlock.cs index 47921f08..1a7000b7 100644 --- a/SlackNet/Blocks/TableBlock.cs +++ b/SlackNet/Blocks/TableBlock.cs @@ -9,7 +9,7 @@ public class TableBlock() : Block("table") public IList ColumnSettings { get; set; } = []; } -public abstract class TableCell(string type) +public abstract class TableCell(string type) : SlackObject { public string Type { get; set; } = type; } @@ -38,7 +38,7 @@ public class RawNumberCell() : TableCell("raw_number") public string Text { get; set; } } -public class TableColumnSettings +public class TableColumnSettings : SlackObject { public ColumnAlignment Align { get; set; } public bool IsWrapped { get; set; } diff --git a/SlackNet/Blocks/TaskCardBlock.cs b/SlackNet/Blocks/TaskCardBlock.cs index 3a1cb789..4faf9df1 100644 --- a/SlackNet/Blocks/TaskCardBlock.cs +++ b/SlackNet/Blocks/TaskCardBlock.cs @@ -54,7 +54,7 @@ public class TaskCardBlock() : Block("task_card") /// /// One of Slack's named task icons. /// -public class TaskCardIcon +public class TaskCardIcon : SlackObject { public string Type { get; set; } = "icon"; diff --git a/SlackNet/Blocks/TextObject.cs b/SlackNet/Blocks/TextObject.cs index c36a443c..60f6fb7b 100644 --- a/SlackNet/Blocks/TextObject.cs +++ b/SlackNet/Blocks/TextObject.cs @@ -3,7 +3,7 @@ /// /// An object containing some text, formatted either as plain text or using Slack's "mrkdwn". /// -public abstract class TextObject +public abstract class TextObject : SlackObject { protected TextObject(string type) { diff --git a/SlackNet/Events/AppContextChanged.cs b/SlackNet/Events/AppContextChanged.cs index 14038d36..db73ecee 100644 --- a/SlackNet/Events/AppContextChanged.cs +++ b/SlackNet/Events/AppContextChanged.cs @@ -17,7 +17,7 @@ public class AppContextChanged : Event /// /// Describes the Slack entities a user is viewing while interacting with an app. /// -public class AppContext +public class AppContext : SlackObject { /// /// The entities the user is currently viewing, ordered by relevance. @@ -28,7 +28,7 @@ public class AppContext /// /// Identifies one Slack entity in the user's current app context. /// -public class AppContextEntity +public class AppContextEntity : SlackObject { /// The kind of entity represented by . public string Type { get; set; } diff --git a/SlackNet/Events/ChannelCreated.cs b/SlackNet/Events/ChannelCreated.cs index 94caeef8..4cc65423 100644 --- a/SlackNet/Events/ChannelCreated.cs +++ b/SlackNet/Events/ChannelCreated.cs @@ -8,7 +8,7 @@ public class ChannelCreated : Event public CreatedChannel Channel { get; set; } } -public class CreatedChannel +public class CreatedChannel : SlackObject { public string Id { get; set; } public string Name { get; set; } diff --git a/SlackNet/Events/ChannelRename.cs b/SlackNet/Events/ChannelRename.cs index fb0e72af..fbf72e38 100644 --- a/SlackNet/Events/ChannelRename.cs +++ b/SlackNet/Events/ChannelRename.cs @@ -8,7 +8,7 @@ public class ChannelRename : Event public RenamedChannel Channel { get; set; } } -public class RenamedChannel +public class RenamedChannel : SlackObject { public string Id { get; set; } public string Name { get; set; } diff --git a/SlackNet/Events/DeletedProfile.cs b/SlackNet/Events/DeletedProfile.cs index 5e038dc6..ddb75c56 100644 --- a/SlackNet/Events/DeletedProfile.cs +++ b/SlackNet/Events/DeletedProfile.cs @@ -2,7 +2,7 @@ namespace SlackNet.Events; -public class DeletedProfile +public class DeletedProfile : SlackObject { public IList Fields { get; set; } } \ No newline at end of file diff --git a/SlackNet/Events/EventRequest.cs b/SlackNet/Events/EventRequest.cs index bd5ca9e6..f39d970a 100644 --- a/SlackNet/Events/EventRequest.cs +++ b/SlackNet/Events/EventRequest.cs @@ -1,6 +1,6 @@ namespace SlackNet.Events; -public class EventRequest +public class EventRequest : SlackObject { public string Type { get; set; } public string Token { get; set; } diff --git a/SlackNet/Events/FileId.cs b/SlackNet/Events/FileId.cs index 12927aef..76fd08e3 100644 --- a/SlackNet/Events/FileId.cs +++ b/SlackNet/Events/FileId.cs @@ -1,6 +1,6 @@ namespace SlackNet.Events; -public class FileId +public class FileId : SlackObject { public string Id { get; set; } } \ No newline at end of file diff --git a/SlackNet/Events/LinkShared.cs b/SlackNet/Events/LinkShared.cs index f597eb0c..d4a6ee52 100644 --- a/SlackNet/Events/LinkShared.cs +++ b/SlackNet/Events/LinkShared.cs @@ -21,7 +21,7 @@ public enum LinkSource Composer } -public class SharedLink +public class SharedLink : SlackObject { public string Domain { get; set; } public string Url { get; set; } diff --git a/SlackNet/Events/Messages/AssistantAppThread.cs b/SlackNet/Events/Messages/AssistantAppThread.cs index 4350f602..ae992052 100644 --- a/SlackNet/Events/Messages/AssistantAppThread.cs +++ b/SlackNet/Events/Messages/AssistantAppThread.cs @@ -12,7 +12,7 @@ public class AssistantAppThread : MessageEvent public AssistantAppThreadInfo AssistantThread { get; set; } } -public class AssistantAppThreadInfo +public class AssistantAppThreadInfo : SlackObject { public string Title { get; set; } public IList TitleBlocks { get; set; } = []; diff --git a/SlackNet/Events/Messages/MessageEvent.cs b/SlackNet/Events/Messages/MessageEvent.cs index 2b91c268..9645f377 100644 --- a/SlackNet/Events/Messages/MessageEvent.cs +++ b/SlackNet/Events/Messages/MessageEvent.cs @@ -32,14 +32,14 @@ public class MessageEvent : MessageEventBase public AppContext AppContext { get; set; } } -public class PinnedInfo +public class PinnedInfo : SlackObject { public string Channel { get; set; } public string PinnedBy { get; set; } public int? PinnedTs { get; set; } } -public class Edit +public class Edit : SlackObject { public string User { get; set; } public string Ts { get; set; } @@ -47,7 +47,7 @@ public class Edit public DateTime Timestamp => Ts.ToDateTime().GetValueOrDefault(); } -public class Reply +public class Reply : SlackObject { public string User { get; set; } public string Ts { get; set; } diff --git a/SlackNet/Events/ReorderedProfile.cs b/SlackNet/Events/ReorderedProfile.cs index 109d6e10..35188087 100644 --- a/SlackNet/Events/ReorderedProfile.cs +++ b/SlackNet/Events/ReorderedProfile.cs @@ -2,7 +2,7 @@ namespace SlackNet.Events; -public class ReorderedProfile +public class ReorderedProfile : SlackObject { public IList Fields { get; set; } } \ No newline at end of file diff --git a/SlackNet/Events/ReorderedProfileField.cs b/SlackNet/Events/ReorderedProfileField.cs index 34d93876..fb57d509 100644 --- a/SlackNet/Events/ReorderedProfileField.cs +++ b/SlackNet/Events/ReorderedProfileField.cs @@ -1,6 +1,6 @@ namespace SlackNet.Events; -public class ReorderedProfileField +public class ReorderedProfileField : SlackObject { public string Id { get; set; } public int Ordering { get; set; } diff --git a/SlackNet/Interaction/ActionElement.cs b/SlackNet/Interaction/ActionElement.cs index e54691c6..d51f0602 100644 --- a/SlackNet/Interaction/ActionElement.cs +++ b/SlackNet/Interaction/ActionElement.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public abstract class ActionElement +public abstract class ActionElement : SlackObject { protected ActionElement(string type) => Type = type; diff --git a/SlackNet/Interaction/BlockOptionsResponse.cs b/SlackNet/Interaction/BlockOptionsResponse.cs index f3a54137..ad682e0b 100644 --- a/SlackNet/Interaction/BlockOptionsResponse.cs +++ b/SlackNet/Interaction/BlockOptionsResponse.cs @@ -2,7 +2,7 @@ namespace SlackNet.Interaction; -public class BlockOptionsResponse +public class BlockOptionsResponse : SlackObject { public IList Options { get; set; } public IList OptionGroups { get; set; } diff --git a/SlackNet/Interaction/Container.cs b/SlackNet/Interaction/Container.cs index 59d9fe51..606bbe12 100644 --- a/SlackNet/Interaction/Container.cs +++ b/SlackNet/Interaction/Container.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public class Container +public class Container : SlackObject { public string Type { get; set; } public string MessageTs { get; set; } diff --git a/SlackNet/Interaction/Dialog.cs b/SlackNet/Interaction/Dialog.cs index 7a9e4c91..198769bf 100644 --- a/SlackNet/Interaction/Dialog.cs +++ b/SlackNet/Interaction/Dialog.cs @@ -2,7 +2,7 @@ namespace SlackNet.Interaction; -public class Dialog +public class Dialog : SlackObject { public string CallbackId { get; set; } public string Title { get; set; } diff --git a/SlackNet/Interaction/DialogElement.cs b/SlackNet/Interaction/DialogElement.cs index 5f5a7d38..976ef10f 100644 --- a/SlackNet/Interaction/DialogElement.cs +++ b/SlackNet/Interaction/DialogElement.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public abstract class DialogElement +public abstract class DialogElement : SlackObject { protected DialogElement(string type) => Type = type; diff --git a/SlackNet/Interaction/DialogError.cs b/SlackNet/Interaction/DialogError.cs index 203eaacb..66b2a20f 100644 --- a/SlackNet/Interaction/DialogError.cs +++ b/SlackNet/Interaction/DialogError.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public class DialogError +public class DialogError : SlackObject { public string Name { get; set; } public string Error { get; set; } diff --git a/SlackNet/Interaction/DialogErrorResponse.cs b/SlackNet/Interaction/DialogErrorResponse.cs index d98e584f..759ad437 100644 --- a/SlackNet/Interaction/DialogErrorResponse.cs +++ b/SlackNet/Interaction/DialogErrorResponse.cs @@ -2,7 +2,7 @@ namespace SlackNet.Interaction; -public class DialogErrorResponse +public class DialogErrorResponse : SlackObject { public IEnumerable Errors { get; set; } } \ No newline at end of file diff --git a/SlackNet/Interaction/InteractionRequest.cs b/SlackNet/Interaction/InteractionRequest.cs index d0130ab5..beb1b3ad 100644 --- a/SlackNet/Interaction/InteractionRequest.cs +++ b/SlackNet/Interaction/InteractionRequest.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public abstract class InteractionRequest +public abstract class InteractionRequest : SlackObject { public string Type { get; set; } public string Token { get; set; } diff --git a/SlackNet/Interaction/MessageResponse.cs b/SlackNet/Interaction/MessageResponse.cs index 5725bb5b..717aabbd 100644 --- a/SlackNet/Interaction/MessageResponse.cs +++ b/SlackNet/Interaction/MessageResponse.cs @@ -7,7 +7,7 @@ public interface IMessageResponse Message Message { get; set; } } -public class MessageResponse : IMessageResponse +public class MessageResponse : SlackObject, IMessageResponse { public ResponseType ResponseType { get; set; } public bool ReplaceOriginal { get; set; } diff --git a/SlackNet/Interaction/OptionsRequestBase.cs b/SlackNet/Interaction/OptionsRequestBase.cs index 87a2fabf..b3dbece3 100644 --- a/SlackNet/Interaction/OptionsRequestBase.cs +++ b/SlackNet/Interaction/OptionsRequestBase.cs @@ -1,6 +1,6 @@ namespace SlackNet.Interaction; -public class OptionsRequestBase +public class OptionsRequestBase : SlackObject { public string Type { get; set; } public string Value { get; set; } diff --git a/SlackNet/Interaction/OptionsResponse.cs b/SlackNet/Interaction/OptionsResponse.cs index 55fc53c0..8f074dd5 100644 --- a/SlackNet/Interaction/OptionsResponse.cs +++ b/SlackNet/Interaction/OptionsResponse.cs @@ -2,7 +2,7 @@ namespace SlackNet.Interaction; -public class OptionsResponse +public class OptionsResponse : SlackObject { public IList