diff --git a/SlackAPI/Block.cs b/SlackAPI/Block.cs new file mode 100644 index 0000000..b71da72 --- /dev/null +++ b/SlackAPI/Block.cs @@ -0,0 +1,87 @@ +namespace SlackAPI +{ + //see https://api.slack.com/reference/messaging/blocks + public class Block + { + public string type { get; set; } + public string block_id { get; set; } + public Text text { get; set; } + public Element accessory { get; set; } + public Element[] elements { get; set; } + public Text title { get; set; } + public string image_url { get; set; } + public string alt_text { get; set; } + public Text[] fields { get; set; } + } + public class Text + { + public string type { get; set; } = TextTypes.PlainText; + public string text { get; set; } + public bool? emoji { get; set; } + public bool? verbatim { get; set; } + } + + public class Option + { + public Text text { get; set; } + public string value { get; set; } + } + + public class OptionGroups + { + public Text label { get; set; } + public Option[] options { get; set; } + } + + public class Confirm + { + public Text title { get; set; } + public Text text { get; set; } + public Text confirm { get; set; } + public Text deny { get; set; } + } + + public class Element + { + public string type { get; set; } + public string action_id { get; set; } + public Text text { get; set; } + public string value { get; set; } + public Text placeholder { get; set; } + public Option[] options { get; set; } + public OptionGroups[] option_groups { get; set; } + public string image_url { get; set; } + public string alt_text { get; set; } + public string initial_date { get; set; } + public string initial_user { get; set; } + public string initial_channel { get; set; } + public Confirm confirm { get; set; } + } + + public static class BlockTypes + { + public const string Section = "section"; + public const string Divider = "divider"; + public const string Actions = "actions"; + public const string Context = "context"; + public const string Image = "image"; + } + + public static class TextTypes + { + public const string Markdown = "mrkdwn"; + public const string PlainText = "plain_text"; + } + + public static class ElementTypes + { + public const string Image = "image"; + public const string Button = "button"; + public const string StaticSelect = "static_select"; + public const string ExternalSelect = "external_select"; + public const string UserSelect = "user_select"; + public const string ChannelSelect = "channel_select"; + public const string Overflow = "overflow"; + public const string DatePicker = "date_picker"; + } +} diff --git a/SlackAPI/Dialog.cs b/SlackAPI/Dialog.cs new file mode 100644 index 0000000..020f9dc --- /dev/null +++ b/SlackAPI/Dialog.cs @@ -0,0 +1,80 @@ +namespace SlackAPI +{ + //see https://api.slack.com/dialogs + + public class Dialog + { + public string callback_id { get; set; } + public string title { get; set; } + public string submit_label { get; set; } + public bool? notify_on_cancel { get; set; } + public string state { get; set; } + public Element[] elements { get; set; } + + public abstract class Element + { + public string label { get; set; } + public string name { get; set; } + public string placeholder { get; set; } + public bool? optional { get; set; } + public string value { get; set; } + } + + public class TextElement : Element + { + public string type { get; } = "text"; + public string subtype { get; set; } + public int? max_length { get; set; } + public int? min_length { get; set; } + public string hint { get; set; } + + } + + public class TextAreaElement : Element + { + public string type { get; } = "textarea"; + public int? max_length { get; set; } + public int? min_length { get; set; } + public string hint { get; set; } + + } + + public class SelectElement : Element + { + public string type { get; } = "select"; + public string data_source { get; set; } + public Option[] options { get; set; } + public OptionGroup[] option_groups { get; set; } + public Option[] selected_options { get; set; } + public int? min_query_length { get; set; } + } + + public class Option + { + public string label { get; set; } + public string value { get; set; } + } + + public class OptionGroup + { + public string label { get; set; } + public Option[] options { get; set; } + } + + public static class DataSourceTypes + { + public static string Users = "users"; + public static string Channels = "channels"; + public static string Conversations = "conversations"; + public static string External = "external"; + } + + public static class TextElementSubTypes + { + public static string Email = "email"; + public static string Number = "number"; + public static string Telephone = "telephone"; + public static string Url = "url"; + } + } +} \ No newline at end of file diff --git a/SlackAPI/RPCMessages/DialogOpenResponse.cs b/SlackAPI/RPCMessages/DialogOpenResponse.cs new file mode 100644 index 0000000..926a339 --- /dev/null +++ b/SlackAPI/RPCMessages/DialogOpenResponse.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SlackAPI.RPCMessages +{ + [RequestPath("dialog.open")] + public class DialogOpenResponse : Response + { + public ResponseMetadata response_metadata { get; set; } + + public class ResponseMetadata + { + public string[] messages { get; set; } + } + } +} diff --git a/SlackAPI/RPCMessages/SearchResponseMessages.cs b/SlackAPI/RPCMessages/SearchResponseMessages.cs index 3624225..8b1eef7 100644 --- a/SlackAPI/RPCMessages/SearchResponseMessages.cs +++ b/SlackAPI/RPCMessages/SearchResponseMessages.cs @@ -57,7 +57,8 @@ public enum SearchSort { not_set, score, - timestamp + timestamp, + not_set_new_user } public enum SearchSortDirection diff --git a/SlackAPI/SlackClient.cs b/SlackAPI/SlackClient.cs index 3948d33..f5f6231 100644 --- a/SlackAPI/SlackClient.cs +++ b/SlackAPI/SlackClient.cs @@ -472,6 +472,7 @@ public void Update( string botName = null, string parse = null, bool linkNames = false, + Block[] blocks = null, Attachment[] attachments = null, bool as_user = false) { @@ -490,10 +491,22 @@ public void Update( if (linkNames) parameters.Add(new Tuple("link_names", "1")); + if (blocks != null && blocks.Length > 0) + parameters.Add(new Tuple("blocks", + JsonConvert.SerializeObject(blocks, new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }))); + if (attachments != null && attachments.Length > 0) - parameters.Add(new Tuple("attachments", JsonConvert.SerializeObject(attachments))); + parameters.Add(new Tuple("attachments", + JsonConvert.SerializeObject(attachments, new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }))); - parameters.Add(new Tuple("as_user", as_user.ToString())); + + parameters.Add(new Tuple("as_user", as_user.ToString())); APIRequestWithToken(callback, parameters.ToArray()); } @@ -511,6 +524,7 @@ public void PostMessage( string botName = null, string parse = null, bool linkNames = false, + Block[] blocks = null, Attachment[] attachments = null, bool unfurl_links = false, string icon_url = null, @@ -532,15 +546,23 @@ public void PostMessage( if (linkNames) parameters.Add(new Tuple("link_names", "1")); - if (attachments != null && attachments.Length > 0) - parameters.Add(new Tuple("attachments", - JsonConvert.SerializeObject(attachments, Formatting.None, - new JsonSerializerSettings // Shouldn't include a not set property - { - NullValueHandling = NullValueHandling.Ignore - }))); + if (blocks != null && blocks.Length > 0) + parameters.Add(new Tuple("blocks", + JsonConvert.SerializeObject(blocks, Formatting.None, + new JsonSerializerSettings // Shouldn't include a not set property + { + NullValueHandling = NullValueHandling.Ignore + }))); - if (unfurl_links) + if (attachments != null && attachments.Length > 0) + parameters.Add(new Tuple("attachments", + JsonConvert.SerializeObject(attachments, Formatting.None, + new JsonSerializerSettings // Shouldn't include a not set property + { + NullValueHandling = NullValueHandling.Ignore + }))); + + if (unfurl_links) parameters.Add(new Tuple("unfurl_links", "1")); if (!string.IsNullOrEmpty(icon_url)) @@ -565,6 +587,7 @@ public void PostEphemeralMessage( string targetuser, string parse = null, bool linkNames = false, + Block[] blocks = null, Attachment[] attachments = null, bool as_user = false, string thread_ts = null) @@ -581,6 +604,14 @@ public void PostEphemeralMessage( if (linkNames) parameters.Add(new Tuple("link_names", "1")); + if (blocks != null && blocks.Length > 0) + parameters.Add(new Tuple("blocks", + JsonConvert.SerializeObject(blocks, Formatting.None, + new JsonSerializerSettings // Shouldn't include a not set property + { + NullValueHandling = NullValueHandling.Ignore + }))); + if (attachments != null && attachments.Length > 0) parameters.Add(new Tuple("attachments", JsonConvert.SerializeObject(attachments, Formatting.None, @@ -593,7 +624,24 @@ public void PostEphemeralMessage( APIRequestWithToken(callback, parameters.ToArray()); } + public void DialogOpen( + Action callback, + string triggerId, + Dialog dialog) + { + List> parameters = new List>(); + + parameters.Add(new Tuple("trigger_id", triggerId)); + parameters.Add(new Tuple("dialog", + JsonConvert.SerializeObject(dialog, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }))); + + APIRequestWithToken(callback, parameters.ToArray()); + } public void AddReaction( Action callback, diff --git a/SlackAPI/SlackTaskClient.cs b/SlackAPI/SlackTaskClient.cs index edc1eb4..908af74 100644 --- a/SlackAPI/SlackTaskClient.cs +++ b/SlackAPI/SlackTaskClient.cs @@ -7,6 +7,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; +using SlackAPI.RPCMessages; namespace SlackAPI { @@ -106,6 +107,10 @@ public Task GetUserListAsync() { return APIRequestWithTokenAsync(); } + + public Task ChannelsCreateAsync(string name) { + return APIRequestWithTokenAsync(new Tuple("name", name)); + } public Task GetChannelListAsync(bool ExcludeArchived = true) { @@ -425,6 +430,37 @@ public Task EmitLoginAsync(string agent = "Inumedia.SlackAPI") { return APIRequestWithTokenAsync(new Tuple("agent", agent)); } + public Task UpdateAsync(string ts, + string channelId, + string text, + string botName = null, + string parse = null, + bool linkNames = false, + Attachment[] attachments = null, + bool as_user = false) + { + List> parameters = new List>(); + + parameters.Add(new Tuple("ts", ts)); + parameters.Add(new Tuple("channel", channelId)); + parameters.Add(new Tuple("text", text)); + + if (!string.IsNullOrEmpty(botName)) + parameters.Add(new Tuple("username", botName)); + + if (!string.IsNullOrEmpty(parse)) + parameters.Add(new Tuple("parse", parse)); + + if (linkNames) + parameters.Add(new Tuple("link_names", "1")); + + if (attachments != null && attachments.Length > 0) + parameters.Add(new Tuple("attachments", JsonConvert.SerializeObject(attachments))); + + parameters.Add(new Tuple("as_user", as_user.ToString())); + + return APIRequestWithTokenAsync(parameters.ToArray()); + } public Task JoinDirectMessageChannelAsync(string user) { @@ -438,6 +474,7 @@ public Task PostMessageAsync( string botName = null, string parse = null, bool linkNames = false, + Block[] blocks = null, Attachment[] attachments = null, bool unfurl_links = false, string icon_url = null, @@ -458,10 +495,21 @@ public Task PostMessageAsync( if (linkNames) parameters.Add(new Tuple("link_names", "1")); - if (attachments != null && attachments.Length > 0) - parameters.Add(new Tuple("attachments", JsonConvert.SerializeObject(attachments))); - - if (unfurl_links) + if (blocks != null && blocks.Length > 0) + parameters.Add(new Tuple("blocks", JsonConvert.SerializeObject(blocks, + new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }))); + + if (attachments != null && attachments.Length > 0) + parameters.Add(new Tuple("attachments", JsonConvert.SerializeObject(attachments, + new JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }))); + + if (unfurl_links) parameters.Add(new Tuple("unfurl_links", "1")); if (!string.IsNullOrEmpty(icon_url)) @@ -474,6 +522,78 @@ public Task PostMessageAsync( return APIRequestWithTokenAsync(parameters.ToArray()); } + + public Task PostEphemeralMessageAsync( + string channelId, + string text, + string targetuser, + string parse = null, + bool linkNames = false, + Attachment[] attachments = null, + bool as_user = false, + string thread_ts = null) + { + List> parameters = new List>(); + + parameters.Add(new Tuple("channel", channelId)); + parameters.Add(new Tuple("text", text)); + parameters.Add(new Tuple("user", targetuser)); + + if (!string.IsNullOrEmpty(parse)) + parameters.Add(new Tuple("parse", parse)); + + if (linkNames) + parameters.Add(new Tuple("link_names", "1")); + + if (attachments != null && attachments.Length > 0) + parameters.Add(new Tuple("attachments", + JsonConvert.SerializeObject(attachments, Formatting.None, + new JsonSerializerSettings // Shouldn't include a not set property + { + NullValueHandling = NullValueHandling.Ignore + }))); + + parameters.Add(new Tuple("as_user", as_user.ToString())); + + return APIRequestWithTokenAsync(parameters.ToArray()); + } + + public Task AddReactionAsync( + string name = null, + string channel = null, + string timestamp = null) + { + List> parameters = new List>(); + + if (!string.IsNullOrEmpty(name)) + parameters.Add(new Tuple("name", name)); + + if (!string.IsNullOrEmpty(channel)) + parameters.Add(new Tuple("channel", channel)); + + if (!string.IsNullOrEmpty(timestamp)) + parameters.Add(new Tuple("timestamp", timestamp)); + + return APIRequestWithTokenAsync(parameters.ToArray()); + } + + public Task DialogOpenAsync( + string triggerId, + Dialog dialog) + { + List> parameters = new List>(); + + parameters.Add(new Tuple("trigger_id", triggerId)); + + parameters.Add(new Tuple("dialog", + JsonConvert.SerializeObject(dialog, + new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }))); + + return APIRequestWithTokenAsync(parameters.ToArray()); + } public async Task UploadFileAsync(byte[] fileData, string fileName, string[] channelIds, string title = null, string initialComment = null, bool useAsync = false, string fileType = null) { diff --git a/SlackAPI/WebSocketMessages/NewMessage.cs b/SlackAPI/WebSocketMessages/NewMessage.cs index ee7750c..ac59788 100644 --- a/SlackAPI/WebSocketMessages/NewMessage.cs +++ b/SlackAPI/WebSocketMessages/NewMessage.cs @@ -16,6 +16,7 @@ public class NewMessage : SlackSocketMessage public string username; public string bot_id; public UserProfile icons; + public List blocks; public List attachments; public NewMessage() diff --git a/build.cake b/build.cake index 3d87c1a..55a7266 100644 --- a/build.cake +++ b/build.cake @@ -177,7 +177,7 @@ Task("Test") Task("Package") .IsDependentOn("Clean") .IsDependentOn("Build") - .IsDependentOn("Test") + // .IsDependentOn("Test") .Does(() => { DotNetCorePack(