diff --git a/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs b/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs index a2c64b737..c67f4c55a 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; namespace NzbDrone.Core.Notifications.Slack.Payloads @@ -12,6 +12,9 @@ namespace NzbDrone.Core.Notifications.Slack.Payloads [JsonProperty("icon_emoji")] public string IconEmoji { get; set; } + [JsonProperty("icon_url")] + public string IconUrl { get; set; } + public List Attachments { get; set; } } } diff --git a/src/NzbDrone.Core/Notifications/Slack/Slack.cs b/src/NzbDrone.Core/Notifications/Slack/Slack.cs index 307ce9616..44614c0ca 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Slack.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Slack.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Notifications.Slack.Payloads; using NzbDrone.Core.Rest; using NzbDrone.Core.Music; @@ -14,10 +16,12 @@ namespace NzbDrone.Core.Notifications.Slack { public class Slack : NotificationBase { + private readonly ISlackProxy _proxy; private readonly Logger _logger; - public Slack(Logger logger) + public Slack(ISlackProxy proxy, Logger logger) { + _proxy = proxy; _logger = logger; } @@ -26,65 +30,51 @@ namespace NzbDrone.Core.Notifications.Slack public override void OnGrab(GrabMessage message) { - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = $"Grabbed: {message.Message}", - Attachments = new List - { - new Attachment - { - Fallback = message.Message, - Title = message.Artist.Name, - Text = message.Message, - Color = "warning" - } - } - }; - - NotifySlack(payload); + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.Artist.Name, + Text = message.Message, + Color = "warning" + } + }; + var payload = CreatePayload($"Grabbed: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); } public override void OnDownload(DownloadMessage message) { - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = $"Imported: {message.Message}", - Attachments = new List - { - new Attachment - { - Fallback = message.Message, - Title = message.Artist.Name, - Text = message.Message, - Color = "good" - } - } - }; - - NotifySlack(payload); + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.Artist.Name, + Text = message.Message, + Color = "good" + } + }; + var payload = CreatePayload($"Imported: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); } public override void OnRename(Artist artist) { - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = "Renamed", - Attachments = new List - { - new Attachment - { - Title = artist.Name, - } - } - }; + var attachments = new List + { + new Attachment + { + Title = artist.Name, + } + }; + + var payload = CreatePayload("Renamed", attachments); - NotifySlack(payload); + _proxy.SendPayload(payload, Settings); } public override ValidationResult Test() @@ -101,14 +91,9 @@ namespace NzbDrone.Core.Notifications.Slack try { var message = $"Test message from Lidarr posted at {DateTime.Now}"; - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = message - }; + var payload = CreatePayload(message); - NotifySlack(payload); + _proxy.SendPayload(payload, Settings); } catch (SlackExeption ex) @@ -119,24 +104,31 @@ namespace NzbDrone.Core.Notifications.Slack return null; } - private void NotifySlack(SlackPayload payload) + private SlackPayload CreatePayload(string message, List attachments = null) { - try + var icon = Settings.Icon; + + var payload = new SlackPayload { - var client = RestClientFactory.BuildClient(Settings.WebHookUrl); - var request = new RestRequest(Method.POST) - { - RequestFormat = DataFormat.Json, - JsonSerializer = new JsonNetSerializer() - }; - request.AddBody(payload); - client.ExecuteAndValidate(request); - } - catch (RestException ex) + Username = Settings.Username, + Text = message, + Attachments = attachments + }; + + if (icon.IsNotNullOrWhiteSpace()) { - _logger.Error(ex, "Unable to post payload {0}", payload); - throw new SlackExeption("Unable to post payload", ex); + // Set the correct icon based on the value + if (icon.StartsWith(":") && icon.EndsWith(":")) + { + payload.IconEmoji = icon; + } + else + { + payload.IconUrl = icon; + } } + + return payload; } } } diff --git a/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs b/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs new file mode 100644 index 000000000..f510464d3 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Slack/SlackProxy.cs @@ -0,0 +1,46 @@ +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Notifications.Slack.Payloads; +using NzbDrone.Core.Rest; + +namespace NzbDrone.Core.Notifications.Slack +{ + public interface ISlackProxy + { + void SendPayload(SlackPayload payload, SlackSettings settings); + } + + public class SlackProxy : ISlackProxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public SlackProxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public void SendPayload(SlackPayload payload, SlackSettings settings) + { + try + { + var request = new HttpRequestBuilder(settings.WebHookUrl) + .Accept(HttpAccept.Json) + .Build(); + + request.Method = HttpMethod.POST; + request.Headers.ContentType = "application/json"; + request.SetContent(payload.ToJson()); + + _httpClient.Execute(request); + } + catch (RestException ex) + { + _logger.Error(ex, "Unable to post payload {0}", payload); + throw new SlackExeption("Unable to post payload", ex); + } + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs index f64daddb5..80fbfce0e 100644 --- a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs +++ b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Notifications.Slack [FieldDefinition(1, Label = "Username", HelpText = "Choose the username that this integration will post as", Type = FieldType.Textbox)] public string Username { get; set; } - [FieldDefinition(2, Label = "Icon", HelpText = "Change the icon that is used for messages from this integration", Type = FieldType.Textbox, HelpLink = "http://www.emoji-cheat-sheet.com/")] + [FieldDefinition(2, Label = "Icon", HelpText = "Change the icon that is used for messages from this integration (Emoji or URL)", Type = FieldType.Textbox, HelpLink = "http://www.emoji-cheat-sheet.com/")] public string Icon { get; set; } public NzbDroneValidationResult Validate() diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 993403028..af5bc22b8 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -804,6 +804,7 @@ +