diff --git a/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs b/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs index a2c64b737..09953c115 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Payloads/SlackPayload.cs @@ -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 13e69f5a0..471986dc7 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.Tv; @@ -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; } @@ -27,86 +31,68 @@ 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.Movie.Title, - Text = message.Message, - Color = "warning" - } - } - }; - - NotifySlack(payload); + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.Movie.Title, + 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.Movie.Title, - Text = message.Message, - Color = "good" - } - } - }; - - NotifySlack(payload); + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.Movie.Title, + Text = message.Message, + Color = "good" + } + }; + var payload = CreatePayload($"Imported: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); } public override void OnMovieRename(Movie movie) { - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = "Renamed", - Attachments = new List - { - new Attachment - { - Title = movie.Title, - } - } - }; - - NotifySlack(payload); + var attachments = new List + { + new Attachment + { + Title = movie.Title, + } + }; + + var payload = CreatePayload("Renamed", attachments); + + _proxy.SendPayload(payload, Settings); } public override void OnRename(Series series) { - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = "Renamed", - Attachments = new List - { - new Attachment - { - Title = series.Title, - } - } - }; + var attachments = new List + { + new Attachment + { + Title = series.Title, + } + }; - NotifySlack(payload); - } + var payload = CreatePayload("Renamed", attachments); + _proxy.SendPayload(payload, Settings); + } + public override ValidationResult Test() { var failures = new List(); @@ -121,14 +107,10 @@ namespace NzbDrone.Core.Notifications.Slack try { var message = $"Test message from Radarr posted at {DateTime.Now}"; - var payload = new SlackPayload - { - IconEmoji = Settings.Icon, - Username = Settings.Username, - Text = message - }; - NotifySlack(payload); + var payload = CreatePayload(message); + + _proxy.SendPayload(payload, Settings); } catch (SlackExeption ex) @@ -139,24 +121,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..75d1293f8 --- /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); + } + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs index f64daddb5..bef9b5d69 100644 --- a/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs +++ b/src/NzbDrone.Core/Notifications/Slack/SlackSettings.cs @@ -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 6a3d474cc..df8451e87 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -970,6 +970,7 @@ +