Notifications can be tested
Notification ImplementationType was added for showing in UI (Humanized/Title cased of Implementation)
This commit is contained in:
parent
1f4cf0034e
commit
8cac7ed1cd
|
@ -8,6 +8,7 @@ namespace NzbDrone.Api.Notifications
|
||||||
public class NotificationResource : RestResource
|
public class NotificationResource : RestResource
|
||||||
{
|
{
|
||||||
public String Name { get; set; }
|
public String Name { get; set; }
|
||||||
|
public String ImplementationName { get; set; }
|
||||||
public Boolean OnGrab { get; set; }
|
public Boolean OnGrab { get; set; }
|
||||||
public Boolean OnDownload { get; set; }
|
public Boolean OnDownload { get; set; }
|
||||||
public List<Field> Fields { get; set; }
|
public List<Field> Fields { get; set; }
|
||||||
|
|
|
@ -42,8 +42,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
||||||
.Returns(stream);
|
.Returns(stream);
|
||||||
|
|
||||||
|
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
||||||
var result = Mocker.Resolve<PlexProvider>().GetSectionKeys("localhost:32400");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(1);
|
||||||
|
@ -62,7 +61,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
.Returns(stream);
|
.Returns(stream);
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<PlexProvider>().GetSectionKeys("localhost:32400");
|
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
result.Should().HaveCount(1);
|
||||||
|
@ -80,8 +79,8 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
||||||
.Returns(stream);
|
.Returns(stream);
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<PlexProvider>().GetSectionKeys("localhost:32400");
|
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(2);
|
result.Should().HaveCount(2);
|
||||||
|
@ -100,8 +99,8 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString("http://localhost:32400/library/sections/5/refresh"))
|
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString("http://localhost:32400/library/sections/5/refresh"))
|
||||||
.Returns(response);
|
.Returns(response);
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<PlexProvider>().UpdateSection("localhost:32400", 5);
|
Mocker.Resolve<PlexService>().UpdateSection(new PlexServerSettings { Host = "localhost", Port = 32400 }, 5);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,7 +120,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
.Returns("ok");
|
.Returns("ok");
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<PlexProvider>().Notify(_clientSettings, header, message);
|
Mocker.Resolve<PlexService>().Notify(_clientSettings, header, message);
|
||||||
|
|
||||||
|
|
||||||
fakeHttp.Verify(v => v.DownloadString(expectedUrl), Times.Once());
|
fakeHttp.Verify(v => v.DownloadString(expectedUrl), Times.Once());
|
||||||
|
@ -142,7 +141,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
.Returns("ok");
|
.Returns("ok");
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<PlexProvider>().Notify(_clientSettings, header, message);
|
Mocker.Resolve<PlexService>().Notify(_clientSettings, header, message);
|
||||||
|
|
||||||
|
|
||||||
fakeHttp.Verify(v => v.DownloadString(expectedUrl, "plex", "plex"), Times.Once());
|
fakeHttp.Verify(v => v.DownloadString(expectedUrl, "plex", "plex"), Times.Once());
|
||||||
|
|
|
@ -9,130 +9,40 @@ namespace NzbDrone.Core.Test.NotificationTests
|
||||||
{
|
{
|
||||||
[Explicit]
|
[Explicit]
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ProwlProviderTest : CoreTest
|
public class ProwlProviderTest : CoreTest<ProwlService>
|
||||||
{
|
{
|
||||||
private const string _apiKey = "c3bdc0f48168f72d546cc6872925b160f5cbffc1";
|
private const string _apiKey = "66e9f688b512152eb2688f0486ae542c76e564a2";
|
||||||
private const string _apiKey2 = "46a710a46b111b0b8633819b0d8a1e0272a3affa";
|
|
||||||
|
|
||||||
private const string _badApiKey = "1234567890abcdefghijklmnopqrstuvwxyz1234";
|
private const string _badApiKey = "1234567890abcdefghijklmnopqrstuvwxyz1234";
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Verify_should_return_true_for_a_valid_apiKey()
|
public void Verify_should_not_throw_for_a_valid_apiKey()
|
||||||
{
|
{
|
||||||
|
Subject.Verify(_apiKey);
|
||||||
|
ExceptionVerification.ExpectedWarns(0);
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().Verify(_apiKey);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Verify_should_return_false_for_an_invalid_apiKey()
|
public void Verify_should_throw_for_an_invalid_apiKey()
|
||||||
{
|
{
|
||||||
|
Assert.Throws<InvalidApiKeyException>(() => Subject.Verify(_badApiKey));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().Verify(_badApiKey);
|
|
||||||
|
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
result.Should().BeFalse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SendNotification_should_return_true_for_a_valid_apiKey()
|
public void SendNotification_should_not_throw_for_a_valid_apiKey()
|
||||||
{
|
{
|
||||||
|
Subject.SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _apiKey);
|
||||||
|
ExceptionVerification.ExpectedWarns(0);
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _apiKey);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SendNotification_should_return_false_for_an_invalid_apiKey()
|
public void SendNotification_should_log_a_warning_for_an_invalid_apiKey()
|
||||||
{
|
{
|
||||||
|
Subject.SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _badApiKey);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _badApiKey);
|
|
||||||
|
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
result.Should().BeFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_should_alert_with_high_priority()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone (High)", _apiKey, NotificationPriority.High);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_should_alert_with_VeryLow_priority()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone (VeryLow)", _apiKey, NotificationPriority.VeryLow);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_should_have_a_call_back_url()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _apiKey, NotificationPriority.Normal, "http://www.nzbdrone.com");
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_should_return_true_for_two_valid_apiKey()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _apiKey + ", " + _apiKey2);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SendNotification_should_return_true_for_valid_apiKey_with_bad_apiKey()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<ProwlProvider>().SendNotification("NzbDrone Test", "This is a test message from NzbDrone", _apiKey + ", " + _badApiKey);
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().BeTrue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -185,7 +185,6 @@
|
||||||
<Compile Include="DecisionEngineTests\QualityUpgradableSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\QualityUpgradableSpecificationFixture.cs" />
|
||||||
<Compile Include="ProviderTests\DiskProviderTests\FreeDiskSpaceTest.cs" />
|
<Compile Include="ProviderTests\DiskProviderTests\FreeDiskSpaceTest.cs" />
|
||||||
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
|
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
|
||||||
<Compile Include="NotificationTests\GrowlProviderTest.cs" />
|
|
||||||
<Compile Include="ProviderTests\DiskProviderTests\ExtractArchiveFixture.cs" />
|
<Compile Include="ProviderTests\DiskProviderTests\ExtractArchiveFixture.cs" />
|
||||||
<Compile Include="ProviderTests\PostDownloadProviderTests\DropFolderImportServiceFixture.cs" />
|
<Compile Include="ProviderTests\PostDownloadProviderTests\DropFolderImportServiceFixture.cs" />
|
||||||
<Compile Include="SeriesStatsTests\SeriesStatisticsFixture.cs" />
|
<Compile Include="SeriesStatsTests\SeriesStatisticsFixture.cs" />
|
||||||
|
|
|
@ -5,9 +5,9 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
{
|
{
|
||||||
public class Email : NotificationBase<EmailSettings>
|
public class Email : NotificationBase<EmailSettings>
|
||||||
{
|
{
|
||||||
private readonly EmailProvider _smtpProvider;
|
private readonly IEmailService _smtpProvider;
|
||||||
|
|
||||||
public Email(EmailProvider smtpProvider)
|
public Email(IEmailService smtpProvider)
|
||||||
{
|
{
|
||||||
_smtpProvider = smtpProvider;
|
_smtpProvider = smtpProvider;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,11 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
get { return "Email"; }
|
get { return "Email"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "Email"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
const string subject = "NzbDrone [TV] - Grabbed";
|
const string subject = "NzbDrone [TV] - Grabbed";
|
||||||
|
|
|
@ -2,19 +2,26 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Email
|
namespace NzbDrone.Core.Notifications.Email
|
||||||
{
|
{
|
||||||
public class EmailProvider
|
public interface IEmailService
|
||||||
|
{
|
||||||
|
void SendEmail(EmailSettings settings, string subject, string body, bool htmlBody = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EmailService : IEmailService, IExecute<TestEmailCommand>
|
||||||
{
|
{
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public EmailProvider(Logger logger)
|
public EmailService(Logger logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SendEmail(EmailSettings settings, string subject, string body, bool htmlBody = false)
|
public void SendEmail(EmailSettings settings, string subject, string body, bool htmlBody = false)
|
||||||
{
|
{
|
||||||
var email = new MailMessage();
|
var email = new MailMessage();
|
||||||
email.From = new MailAddress(settings.From);
|
email.From = new MailAddress(settings.From);
|
||||||
|
@ -32,7 +39,7 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Send(email, settings.Server, settings.Port, settings.UseSsl, credentials);
|
Send(email, settings.Server, settings.Port, settings.Ssl, credentials);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -41,7 +48,7 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Send(MailMessage email, string server, int port, bool ssl, NetworkCredential credentials)
|
private void Send(MailMessage email, string server, int port, bool ssl, NetworkCredential credentials)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -60,5 +67,15 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Execute(TestEmailCommand message)
|
||||||
|
{
|
||||||
|
var settings = new EmailSettings();
|
||||||
|
settings.InjectFrom(message);
|
||||||
|
|
||||||
|
var body = "Success! You have properly configured your email notification settings";
|
||||||
|
|
||||||
|
SendEmail(settings, "NzbDrone - Test Notification", body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,16 +11,16 @@ namespace NzbDrone.Core.Notifications.Email
|
||||||
[FieldDefinition(1, Label = "Port")]
|
[FieldDefinition(1, Label = "Port")]
|
||||||
public Int32 Port { get; set; }
|
public Int32 Port { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(2, Label = "Use SSL", HelpText = "Does your Email server use SSL?")]
|
[FieldDefinition(2, Label = "SSL", Type = FieldType.Checkbox)]
|
||||||
public Boolean UseSsl { get; set; }
|
public Boolean Ssl { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(3, Label = "Username")]
|
[FieldDefinition(3, Label = "Username")]
|
||||||
public String Username { get; set; }
|
public String Username { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(4, Label = "Password")]
|
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
|
||||||
public String Password { get; set; }
|
public String Password { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(5, Label = "Sender Address")]
|
[FieldDefinition(5, Label = "From Address")]
|
||||||
public String From { get; set; }
|
public String From { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(6, Label = "Recipient Address")]
|
[FieldDefinition(6, Label = "Recipient Address")]
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Email
|
||||||
|
{
|
||||||
|
public class TestEmailCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Server { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public bool Ssl { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string From { get; set; }
|
||||||
|
public string To { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,9 +7,9 @@ namespace NzbDrone.Core.Notifications.Growl
|
||||||
{
|
{
|
||||||
public class Growl : NotificationBase<GrowlSettings>
|
public class Growl : NotificationBase<GrowlSettings>
|
||||||
{
|
{
|
||||||
private readonly GrowlProvider _growlProvider;
|
private readonly IGrowlService _growlProvider;
|
||||||
|
|
||||||
public Growl(GrowlProvider growlProvider)
|
public Growl(IGrowlService growlProvider)
|
||||||
{
|
{
|
||||||
_growlProvider = growlProvider;
|
_growlProvider = growlProvider;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@ namespace NzbDrone.Core.Notifications.Growl
|
||||||
get { return "Growl"; }
|
get { return "Growl"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "Growl"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
const string title = "Episode Grabbed";
|
const string title = "Episode Grabbed";
|
||||||
|
|
|
@ -3,43 +3,33 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Growl.Connector;
|
using Growl.Connector;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
using GrowlNotification = Growl.Connector.Notification;
|
using GrowlNotification = Growl.Connector.Notification;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Growl
|
namespace NzbDrone.Core.Notifications.Growl
|
||||||
{
|
{
|
||||||
public class GrowlProvider
|
public interface IGrowlService
|
||||||
|
{
|
||||||
|
void SendNotification(string title, string message, string notificationTypeName, string hostname, int port, string password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrowlService : IGrowlService, IExecute<TestGrowlCommand>
|
||||||
{
|
{
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private readonly Application _growlApplication = new Application("NzbDrone");
|
private readonly Application _growlApplication = new Application("NzbDrone");
|
||||||
private GrowlConnector _growlConnector;
|
private GrowlConnector _growlConnector;
|
||||||
private List<NotificationType> _notificationTypes;
|
private readonly List<NotificationType> _notificationTypes;
|
||||||
|
|
||||||
public GrowlProvider()
|
public GrowlService()
|
||||||
{
|
{
|
||||||
_notificationTypes = GetNotificationTypes();
|
_notificationTypes = GetNotificationTypes();
|
||||||
_growlApplication.Icon = "https://github.com/NzbDrone/NzbDrone/raw/master/NzbDrone.Core/NzbDrone.jpg";
|
_growlApplication.Icon = "https://github.com/NzbDrone/NzbDrone/raw/master/NzbDrone.Core/NzbDrone.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Register(string hostname, int port, string password)
|
public void SendNotification(string title, string message, string notificationTypeName, string hostname, int port, string password)
|
||||||
{
|
|
||||||
Logger.Trace("Registering NzbDrone with Growl host: {0}:{1}", hostname, port);
|
|
||||||
_growlConnector = new GrowlConnector(password, hostname, port);
|
|
||||||
_growlConnector.Register(_growlApplication, _notificationTypes.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void TestNotification(string hostname, int port, string password)
|
|
||||||
{
|
|
||||||
const string title = "Test Notification";
|
|
||||||
const string message = "This is a test message from NzbDrone";
|
|
||||||
|
|
||||||
SendNotification(title, message, "TEST", hostname, port, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void SendNotification(string title, string message, string notificationTypeName, string hostname, int port, string password)
|
|
||||||
{
|
{
|
||||||
var notificationType = _notificationTypes.Single(n => n.Name == notificationTypeName);
|
var notificationType = _notificationTypes.Single(n => n.Name == notificationTypeName);
|
||||||
|
|
||||||
var notification = new GrowlNotification("NzbDrone", notificationType.Name, DateTime.Now.Ticks.ToString(), title, message);
|
var notification = new GrowlNotification("NzbDrone", notificationType.Name, DateTime.Now.Ticks.ToString(), title, message);
|
||||||
|
|
||||||
_growlConnector = new GrowlConnector(password, hostname, port);
|
_growlConnector = new GrowlConnector(password, hostname, port);
|
||||||
|
@ -48,6 +38,13 @@ namespace NzbDrone.Core.Notifications.Growl
|
||||||
_growlConnector.Notify(notification);
|
_growlConnector.Notify(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Register(string host, int port, string password)
|
||||||
|
{
|
||||||
|
Logger.Trace("Registering NzbDrone with Growl host: {0}:{1}", host, port);
|
||||||
|
_growlConnector = new GrowlConnector(password, host, port);
|
||||||
|
_growlConnector.Register(_growlApplication, _notificationTypes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
private List<NotificationType> GetNotificationTypes()
|
private List<NotificationType> GetNotificationTypes()
|
||||||
{
|
{
|
||||||
var notificationTypes = new List<NotificationType>();
|
var notificationTypes = new List<NotificationType>();
|
||||||
|
@ -57,5 +54,15 @@ namespace NzbDrone.Core.Notifications.Growl
|
||||||
|
|
||||||
return notificationTypes;
|
return notificationTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Execute(TestGrowlCommand message)
|
||||||
|
{
|
||||||
|
Register(message.Host, message.Port, message.Password);
|
||||||
|
|
||||||
|
const string title = "Test Notification";
|
||||||
|
const string body = "This is a test message from NzbDrone";
|
||||||
|
|
||||||
|
SendNotification(title, body, "TEST", message.Host, message.Port, message.Password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Growl
|
||||||
|
{
|
||||||
|
public class TestGrowlCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
public interface INotification
|
public interface INotification
|
||||||
{
|
{
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
|
string ImplementationName { get; }
|
||||||
|
|
||||||
NotificationDefinition InstanceDefinition { get; set; }
|
NotificationDefinition InstanceDefinition { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public string ImplementationName { get; set; }
|
||||||
public bool OnGrab { get; set; }
|
public bool OnGrab { get; set; }
|
||||||
public bool OnDownload { get; set; }
|
public bool OnDownload { get; set; }
|
||||||
public INotifcationSettings Settings { get; set; }
|
public INotifcationSettings Settings { get; set; }
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
public abstract class NotificationBase<TSetting> : INotification where TSetting : class, INotifcationSettings, new()
|
public abstract class NotificationBase<TSetting> : INotification where TSetting : class, INotifcationSettings, new()
|
||||||
{
|
{
|
||||||
public abstract string Name { get; }
|
public abstract string Name { get; }
|
||||||
|
public abstract string ImplementationName { get; }
|
||||||
|
|
||||||
public NotificationDefinition InstanceDefinition { get; set; }
|
public NotificationDefinition InstanceDefinition { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
var newNotification = new Notification();
|
var newNotification = new Notification();
|
||||||
newNotification.Instance = (INotification)_container.Resolve(type);
|
newNotification.Instance = (INotification)_container.Resolve(type);
|
||||||
newNotification.Id = i;
|
newNotification.Id = i;
|
||||||
newNotification.Name = notification.Name;
|
newNotification.ImplementationName = notification.ImplementationName;
|
||||||
|
|
||||||
var instanceType = newNotification.Instance.GetType();
|
var instanceType = newNotification.Instance.GetType();
|
||||||
var baseGenArgs = instanceType.BaseType.GetGenericArguments();
|
var baseGenArgs = instanceType.BaseType.GetGenericArguments();
|
||||||
|
@ -120,6 +120,7 @@ namespace NzbDrone.Core.Notifications
|
||||||
notification.Instance = GetInstance(definition);
|
notification.Instance = GetInstance(definition);
|
||||||
notification.Name = definition.Name;
|
notification.Name = definition.Name;
|
||||||
notification.Implementation = definition.Implementation;
|
notification.Implementation = definition.Implementation;
|
||||||
|
notification.ImplementationName = notification.Instance.ImplementationName;
|
||||||
notification.Settings = ((dynamic)notification.Instance).ImportSettingsFromJson(definition.Settings);
|
notification.Settings = ((dynamic)notification.Instance).ImportSettingsFromJson(definition.Settings);
|
||||||
|
|
||||||
return notification;
|
return notification;
|
||||||
|
|
|
@ -6,9 +6,9 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
{
|
{
|
||||||
public class PlexClient : NotificationBase<PlexClientSettings>
|
public class PlexClient : NotificationBase<PlexClientSettings>
|
||||||
{
|
{
|
||||||
private readonly PlexProvider _plexProvider;
|
private readonly IPlexService _plexProvider;
|
||||||
|
|
||||||
public PlexClient(PlexProvider plexProvider)
|
public PlexClient(IPlexService plexProvider)
|
||||||
{
|
{
|
||||||
_plexProvider = plexProvider;
|
_plexProvider = plexProvider;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
get { return "Plex Client"; }
|
get { return "Plex Client"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "Plex Client"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
const string header = "NzbDrone [TV] - Grabbed";
|
const string header = "NzbDrone [TV] - Grabbed";
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common;
|
|
||||||
using NzbDrone.Core.Configuration;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Plex
|
|
||||||
{
|
|
||||||
public class PlexProvider
|
|
||||||
{
|
|
||||||
private readonly IHttpProvider _httpProvider;
|
|
||||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
public PlexProvider(IHttpProvider httpProvider)
|
|
||||||
{
|
|
||||||
_httpProvider = httpProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Notify(PlexClientSettings settings, string header, string message)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", header, message);
|
|
||||||
SendCommand(settings.Host, settings.Port, command, settings.Username, settings.Password);
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
logger.WarnException("Failed to send notification to Plex Client: " + settings.Host, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void UpdateLibrary(string host)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
logger.Trace("Sending Update Request to Plex Server");
|
|
||||||
var sections = GetSectionKeys(host);
|
|
||||||
sections.ForEach(s => UpdateSection(host, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
logger.WarnException("Failed to Update Plex host: " + host, ex);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<int> GetSectionKeys(string host)
|
|
||||||
{
|
|
||||||
logger.Trace("Getting sections from Plex host: {0}", host);
|
|
||||||
var url = String.Format("http://{0}/library/sections", host);
|
|
||||||
var xmlStream = _httpProvider.DownloadStream(url, null);
|
|
||||||
var xDoc = XDocument.Load(xmlStream);
|
|
||||||
var mediaContainer = xDoc.Descendants("MediaContainer").FirstOrDefault();
|
|
||||||
var directories = mediaContainer.Descendants("Directory").Where(x => x.Attribute("type").Value == "show");
|
|
||||||
|
|
||||||
return directories.Select(d => Int32.Parse(d.Attribute("key").Value)).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateSection(string host, int key)
|
|
||||||
{
|
|
||||||
logger.Trace("Updating Plex host: {0}, Section: {1}", host, key);
|
|
||||||
var url = String.Format("http://{0}/library/sections/{1}/refresh", host, key);
|
|
||||||
_httpProvider.DownloadString(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string SendCommand(string host, int port, string command, string username, string password)
|
|
||||||
{
|
|
||||||
var url = String.Format("http://{0}:{1}/xbmcCmds/xbmcHttp?command={2}", host, port, command);
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(username))
|
|
||||||
{
|
|
||||||
return _httpProvider.DownloadString(url, username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _httpProvider.DownloadString(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void TestNotification(string host, int port, string username, string password)
|
|
||||||
{
|
|
||||||
logger.Trace("Sending Test Notifcation to XBMC Host: {0}", host);
|
|
||||||
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", "Test Notification", "Success! Notifications are setup correctly");
|
|
||||||
SendCommand(host, port, command, username, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,9 +6,9 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
{
|
{
|
||||||
public class PlexServer : NotificationBase<PlexServerSettings>
|
public class PlexServer : NotificationBase<PlexServerSettings>
|
||||||
{
|
{
|
||||||
private readonly PlexProvider _plexProvider;
|
private readonly IPlexService _plexProvider;
|
||||||
|
|
||||||
public PlexServer(PlexProvider plexProvider)
|
public PlexServer(IPlexService plexProvider)
|
||||||
{
|
{
|
||||||
_plexProvider = plexProvider;
|
_plexProvider = plexProvider;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
get { return "Plex Server"; }
|
get { return "Plex Server"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "Plex Server"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -36,7 +41,7 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
{
|
{
|
||||||
if (Settings.UpdateLibrary)
|
if (Settings.UpdateLibrary)
|
||||||
{
|
{
|
||||||
_plexProvider.UpdateLibrary(Settings.Host);
|
_plexProvider.UpdateLibrary(Settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||||
[FieldDefinition(0, Label = "Host", HelpText = "Plex Server Host (IP or Hostname)")]
|
[FieldDefinition(0, Label = "Host", HelpText = "Plex Server Host (IP or Hostname)")]
|
||||||
public String Host { get; set; }
|
public String Host { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(1, Label = "Update Library", HelpText = "Update Library on Download/Rename")]
|
[FieldDefinition(1, Label = "Port")]
|
||||||
|
public Int32 Port { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(2, Label = "Update Library")]
|
||||||
public Boolean UpdateLibrary { get; set; }
|
public Boolean UpdateLibrary { get; set; }
|
||||||
|
|
||||||
public bool IsValid
|
public bool IsValid
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public interface IPlexService
|
||||||
|
{
|
||||||
|
void Notify(PlexClientSettings settings, string header, string message);
|
||||||
|
void UpdateLibrary(PlexServerSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlexService : IPlexService, IExecute<TestPlexClientCommand>, IExecute<TestPlexServerCommand>
|
||||||
|
{
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public PlexService(IHttpProvider httpProvider, Logger logger)
|
||||||
|
{
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify(PlexClientSettings settings, string header, string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", header, message);
|
||||||
|
SendCommand(settings.Host, settings.Port, command, settings.Username, settings.Password);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.WarnException("Failed to send notification to Plex Client: " + settings.Host, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateLibrary(PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Trace("Sending Update Request to Plex Server");
|
||||||
|
var sections = GetSectionKeys(settings);
|
||||||
|
sections.ForEach(s => UpdateSection(settings, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.WarnException("Failed to Update Plex host: " + settings.Host, ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int> GetSectionKeys(PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
_logger.Trace("Getting sections from Plex host: {0}", settings.Host);
|
||||||
|
var url = String.Format("http://{0}:{1}/library/sections", settings.Host, settings.Port);
|
||||||
|
var xmlStream = _httpProvider.DownloadStream(url, null);
|
||||||
|
var xDoc = XDocument.Load(xmlStream);
|
||||||
|
var mediaContainer = xDoc.Descendants("MediaContainer").FirstOrDefault();
|
||||||
|
var directories = mediaContainer.Descendants("Directory").Where(x => x.Attribute("type").Value == "show");
|
||||||
|
|
||||||
|
return directories.Select(d => Int32.Parse(d.Attribute("key").Value)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSection(PlexServerSettings settings, int key)
|
||||||
|
{
|
||||||
|
_logger.Trace("Updating Plex host: {0}, Section: {1}", settings.Host, key);
|
||||||
|
var url = String.Format("http://{0}:{1}/library/sections/{2}/refresh", settings.Host, settings.Port, key);
|
||||||
|
_httpProvider.DownloadString(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SendCommand(string host, int port, string command, string username, string password)
|
||||||
|
{
|
||||||
|
var url = String.Format("http://{0}:{1}/xbmcCmds/xbmcHttp?command={2}", host, port, command);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(username))
|
||||||
|
{
|
||||||
|
return _httpProvider.DownloadString(url, username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _httpProvider.DownloadString(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestPlexClientCommand message)
|
||||||
|
{
|
||||||
|
_logger.Trace("Sending Test Notifcation to Plex Client: {0}", message.Host);
|
||||||
|
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", "Test Notification", "Success! Notifications are setup correctly");
|
||||||
|
var result = SendCommand(message.Host, message.Port, command, message.Username, message.Password);
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(result) ||
|
||||||
|
result.IndexOf("error", StringComparison.InvariantCultureIgnoreCase) > -1)
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to connect to Plex Client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestPlexServerCommand message)
|
||||||
|
{
|
||||||
|
if (!GetSectionKeys(new PlexServerSettings {Host = message.Host, Port = message.Port}).Any())
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to connect to Plex Server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class TestPlexClientCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class TestPlexServerCommand : ICommand
|
||||||
|
{
|
||||||
|
public string Host { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Prowl
|
||||||
|
{
|
||||||
|
public class InvalidApiKeyException : Exception
|
||||||
|
{
|
||||||
|
public InvalidApiKeyException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidApiKeyException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@ namespace NzbDrone.Core.Notifications.Prowl
|
||||||
{
|
{
|
||||||
public class Prowl : NotificationBase<ProwlSettings>
|
public class Prowl : NotificationBase<ProwlSettings>
|
||||||
{
|
{
|
||||||
private readonly ProwlProvider _prowlProvider;
|
private readonly IProwlService _prowlProvider;
|
||||||
|
|
||||||
public Prowl(ProwlProvider prowlProvider)
|
public Prowl(IProwlService prowlProvider)
|
||||||
{
|
{
|
||||||
_prowlProvider = prowlProvider;
|
_prowlProvider = prowlProvider;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,11 @@ namespace NzbDrone.Core.Notifications.Prowl
|
||||||
get { return "Prowl"; }
|
get { return "Prowl"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "Prowl"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
const string title = "Episode Grabbed";
|
const string title = "Episode Grabbed";
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
using System;
|
|
||||||
using NLog;
|
|
||||||
using Prowlin;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Notifications.Prowl
|
|
||||||
{
|
|
||||||
public class ProwlProvider
|
|
||||||
{
|
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
public virtual bool Verify(string apiKey)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var verificationRequest = new Verification();
|
|
||||||
verificationRequest.ApiKey = apiKey;
|
|
||||||
|
|
||||||
var client = new ProwlClient();
|
|
||||||
|
|
||||||
Logger.Trace("Verifying API Key: {0}", apiKey);
|
|
||||||
|
|
||||||
var verificationResult = client.SendVerification(verificationRequest);
|
|
||||||
if (String.IsNullOrWhiteSpace(verificationResult.ErrorMessage) && verificationResult.ResultCode == "200")
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.TraceException(ex.Message, ex);
|
|
||||||
Logger.Warn("Invalid API Key: {0}", apiKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool SendNotification(string title, string message, string apiKey, NotificationPriority priority = NotificationPriority.Normal, string url = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var notification = new Prowlin.Notification
|
|
||||||
{
|
|
||||||
Application = "NzbDrone",
|
|
||||||
Description = message,
|
|
||||||
Event = title,
|
|
||||||
Priority = priority,
|
|
||||||
Url = url
|
|
||||||
};
|
|
||||||
|
|
||||||
notification.AddApiKey(apiKey.Trim());
|
|
||||||
|
|
||||||
var client = new ProwlClient();
|
|
||||||
|
|
||||||
Logger.Trace("Sending Prowl Notification");
|
|
||||||
|
|
||||||
var notificationResult = client.SendNotification(notification);
|
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(notificationResult.ErrorMessage))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.TraceException(ex.Message, ex);
|
|
||||||
Logger.Warn("Invalid API Key: {0}", apiKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void TestNotification(string apiKeys)
|
|
||||||
{
|
|
||||||
const string title = "Test Notification";
|
|
||||||
const string message = "This is a test message from NzbDrone";
|
|
||||||
|
|
||||||
SendNotification(title, message, apiKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
using Prowlin;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Prowl
|
||||||
|
{
|
||||||
|
public interface IProwlService
|
||||||
|
{
|
||||||
|
void SendNotification(string title, string message, string apiKey, NotificationPriority priority = NotificationPriority.Normal, string url = null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProwlService : IProwlService, IExecute<TestProwlCommand>
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public ProwlService(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendNotification(string title, string message, string apiKey, NotificationPriority priority = NotificationPriority.Normal, string url = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var notification = new Prowlin.Notification
|
||||||
|
{
|
||||||
|
Application = "NzbDrone",
|
||||||
|
Description = message,
|
||||||
|
Event = title,
|
||||||
|
Priority = priority,
|
||||||
|
Url = url
|
||||||
|
};
|
||||||
|
|
||||||
|
notification.AddApiKey(apiKey.Trim());
|
||||||
|
|
||||||
|
var client = new ProwlClient();
|
||||||
|
|
||||||
|
_logger.Trace("Sending Prowl Notification");
|
||||||
|
|
||||||
|
var notificationResult = client.SendNotification(notification);
|
||||||
|
|
||||||
|
if (!String.IsNullOrWhiteSpace(notificationResult.ErrorMessage))
|
||||||
|
{
|
||||||
|
throw new InvalidApiKeyException("API Key: " + apiKey + " is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.TraceException(ex.Message, ex);
|
||||||
|
_logger.Warn("Invalid API Key: {0}", apiKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Verify(string apiKey)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var verificationRequest = new Verification();
|
||||||
|
verificationRequest.ApiKey = apiKey;
|
||||||
|
|
||||||
|
var client = new ProwlClient();
|
||||||
|
|
||||||
|
_logger.Trace("Verifying API Key: {0}", apiKey);
|
||||||
|
|
||||||
|
var verificationResult = client.SendVerification(verificationRequest);
|
||||||
|
if (!String.IsNullOrWhiteSpace(verificationResult.ErrorMessage) &&
|
||||||
|
verificationResult.ResultCode != "200")
|
||||||
|
{
|
||||||
|
throw new InvalidApiKeyException("API Key: " + apiKey + " is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.TraceException(ex.Message, ex);
|
||||||
|
_logger.Warn("Invalid API Key: {0}", apiKey);
|
||||||
|
throw new InvalidApiKeyException("API Key: " + apiKey + " is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(TestProwlCommand message)
|
||||||
|
{
|
||||||
|
Verify(message.ApiKey);
|
||||||
|
|
||||||
|
const string title = "Test Notification";
|
||||||
|
const string body = "This is a test message from NzbDrone";
|
||||||
|
|
||||||
|
SendNotification(title, body, message.ApiKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Prowl
|
||||||
|
{
|
||||||
|
public class TestProwlCommand : ICommand
|
||||||
|
{
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
public int Priority { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,11 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
||||||
get { return "XBMC"; }
|
get { return "XBMC"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ImplementationName
|
||||||
|
{
|
||||||
|
get { return "XBMC"; }
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnGrab(string message)
|
public override void OnGrab(string message)
|
||||||
{
|
{
|
||||||
const string header = "NzbDrone [TV] - Grabbed";
|
const string header = "NzbDrone [TV] - Grabbed";
|
||||||
|
|
|
@ -266,7 +266,9 @@
|
||||||
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
||||||
<Compile Include="Download\EpisodeGrabbedEvent.cs" />
|
<Compile Include="Download\EpisodeGrabbedEvent.cs" />
|
||||||
<Compile Include="Download\SeriesRenamedEvent.cs" />
|
<Compile Include="Download\SeriesRenamedEvent.cs" />
|
||||||
|
<Compile Include="Notifications\Email\TestEmailCommand.cs" />
|
||||||
<Compile Include="Notifications\Growl\GrowlSettings.cs" />
|
<Compile Include="Notifications\Growl\GrowlSettings.cs" />
|
||||||
|
<Compile Include="Notifications\Growl\TestGrowlCommand.cs" />
|
||||||
<Compile Include="Notifications\NotificationSettingsProvider.cs" />
|
<Compile Include="Notifications\NotificationSettingsProvider.cs" />
|
||||||
<Compile Include="Notifications\INotification.cs" />
|
<Compile Include="Notifications\INotification.cs" />
|
||||||
<Compile Include="Notifications\Notification.cs" />
|
<Compile Include="Notifications\Notification.cs" />
|
||||||
|
@ -324,11 +326,15 @@
|
||||||
<Compile Include="MetadataSource\Trakt\Season.cs" />
|
<Compile Include="MetadataSource\Trakt\Season.cs" />
|
||||||
<Compile Include="MetadataSource\Trakt\Show.cs" />
|
<Compile Include="MetadataSource\Trakt\Show.cs" />
|
||||||
<Compile Include="Notifications\INotifcationSettings.cs" />
|
<Compile Include="Notifications\INotifcationSettings.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\TestPlexServerCommand.cs" />
|
||||||
<Compile Include="Notifications\Plex\PlexServer.cs" />
|
<Compile Include="Notifications\Plex\PlexServer.cs" />
|
||||||
<Compile Include="Notifications\Plex\PlexClientSettings.cs" />
|
<Compile Include="Notifications\Plex\PlexClientSettings.cs" />
|
||||||
<Compile Include="Notifications\Plex\PlexServerSettings.cs" />
|
<Compile Include="Notifications\Plex\PlexServerSettings.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\TestPlexClientCommand.cs" />
|
||||||
|
<Compile Include="Notifications\Prowl\InvalidApiKeyException.cs" />
|
||||||
<Compile Include="Notifications\Prowl\ProwlSettings.cs" />
|
<Compile Include="Notifications\Prowl\ProwlSettings.cs" />
|
||||||
<Compile Include="Notifications\Email\EmailSettings.cs" />
|
<Compile Include="Notifications\Email\EmailSettings.cs" />
|
||||||
|
<Compile Include="Notifications\Prowl\TestProwlCommand.cs" />
|
||||||
<Compile Include="Notifications\Xbmc\HttpApiProvider.cs" />
|
<Compile Include="Notifications\Xbmc\HttpApiProvider.cs" />
|
||||||
<Compile Include="Notifications\Xbmc\IApiProvider.cs" />
|
<Compile Include="Notifications\Xbmc\IApiProvider.cs" />
|
||||||
<Compile Include="Notifications\Xbmc\InvalidXbmcVersionException.cs" />
|
<Compile Include="Notifications\Xbmc\InvalidXbmcVersionException.cs" />
|
||||||
|
@ -454,7 +460,7 @@
|
||||||
<Compile Include="Notifications\Xbmc\Xbmc.cs">
|
<Compile Include="Notifications\Xbmc\Xbmc.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Growl\GrowlProvider.cs">
|
<Compile Include="Notifications\Growl\GrowlService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="History\HistoryService.cs">
|
<Compile Include="History\HistoryService.cs">
|
||||||
|
@ -472,11 +478,11 @@
|
||||||
<Compile Include="MediaFiles\MediaFileService.cs">
|
<Compile Include="MediaFiles\MediaFileService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Plex\PlexProvider.cs" />
|
<Compile Include="Notifications\Plex\PlexService.cs" />
|
||||||
<Compile Include="MediaFiles\DownloadedEpisodesImportService.cs">
|
<Compile Include="MediaFiles\DownloadedEpisodesImportService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Prowl\ProwlProvider.cs">
|
<Compile Include="Notifications\Prowl\ProwlService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Qualities\QualityProfileService.cs">
|
<Compile Include="Qualities\QualityProfileService.cs">
|
||||||
|
@ -492,7 +498,7 @@
|
||||||
<Compile Include="Tv\SeriesService.cs">
|
<Compile Include="Tv\SeriesService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Email\EmailProvider.cs">
|
<Compile Include="Notifications\Email\EmailService.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Notifications\Xbmc\XbmcService.cs">
|
<Compile Include="Notifications\Xbmc\XbmcService.cs">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="add-notification-item span3">
|
<div class="add-notification-item span3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
{{name}}
|
{{implementationName}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -20,7 +20,6 @@ define([
|
||||||
|
|
||||||
addNotification: function () {
|
addNotification: function () {
|
||||||
this.model.set('id', undefined);
|
this.model.set('id', undefined);
|
||||||
this.model.set('name', '');
|
|
||||||
var view = new NzbDrone.Settings.Notifications.EditView({ model: this.model, notificationCollection: this.notificationCollection });
|
var view = new NzbDrone.Settings.Notifications.EditView({ model: this.model, notificationCollection: this.notificationCollection });
|
||||||
NzbDrone.modalRegion.show(view);
|
NzbDrone.modalRegion.show(view);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
<th>On Grab</th>
|
<th>On Grab</th>
|
||||||
<th>On Download</th>
|
<th>On Download</th>
|
||||||
<th>Controls</th>
|
<th>Controls</th>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
{{#if id}}
|
{{#if id}}
|
||||||
<h3>Edit</h3>
|
<h3>Edit - {{implementationName}}</h3>
|
||||||
{{else}}
|
{{else}}
|
||||||
<h3>Add</h3>
|
<h3>Add - {{implementationName}}</h3>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<td name="name"></td>
|
<td name="name"></td>
|
||||||
|
<td name="implementationName"></td>
|
||||||
<td name="onGrab"></td>
|
<td name="onGrab"></td>
|
||||||
<td name="onDownload"></td>
|
<td name="onDownload"></td>
|
||||||
<td name="cutoff.name"></td>
|
<td name="cutoff.name"></td>
|
||||||
|
|
Loading…
Reference in New Issue