From 3fe1f13bd16d2732e22003d8f7ea3989e31e1aa5 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 24 Mar 2016 17:14:45 +0000 Subject: [PATCH] Refactored the Notification service to how it should have really been done in the first place. --- PlexRequests.Api.Interfaces/IPushbulletApi.cs | 4 +- PlexRequests.Api.Interfaces/IPushoverApi.cs | 3 +- PlexRequests.Api/PushbulletApi.cs | 5 +- PlexRequests.Api/PushoverApi.cs | 7 +- .../NotificationServiceTests.cs | 91 +++++++++++-------- .../INotification.cs | 20 ++-- .../Interfaces/INotificationService.cs | 40 ++++++++ .../Notification/EmailMessageNotification.cs | 44 ++++----- .../Notification/NotificationService.cs | 59 +++++------- .../Notification/PushbulletNotification.cs | 38 ++++---- .../Notification/PushoverNotification.cs | 38 ++++---- .../PlexRequests.Services.csproj | 3 +- PlexRequests.UI.Tests/AdminModuleTests.cs | 4 + PlexRequests.UI/Bootstrapper.cs | 11 ++- PlexRequests.UI/Modules/AdminModule.cs | 7 +- PlexRequests.UI/Modules/RequestsModule.cs | 7 +- PlexRequests.UI/Modules/SearchModule.cs | 5 +- 17 files changed, 220 insertions(+), 166 deletions(-) rename PlexRequests.Services/{Notification => Interfaces}/INotification.cs (75%) create mode 100644 PlexRequests.Services/Interfaces/INotificationService.cs diff --git a/PlexRequests.Api.Interfaces/IPushbulletApi.cs b/PlexRequests.Api.Interfaces/IPushbulletApi.cs index 647280aaf..5df902d4c 100644 --- a/PlexRequests.Api.Interfaces/IPushbulletApi.cs +++ b/PlexRequests.Api.Interfaces/IPushbulletApi.cs @@ -24,6 +24,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion +using System.Threading.Tasks; + using PlexRequests.Api.Models.Notifications; namespace PlexRequests.Api.Interfaces @@ -38,6 +40,6 @@ namespace PlexRequests.Api.Interfaces /// The message. /// The device identifier. /// - PushbulletResponse Push(string accessToken, string title, string message, string deviceIdentifier = default(string)); + Task PushAsync(string accessToken, string title, string message, string deviceIdentifier = default(string)); } } \ No newline at end of file diff --git a/PlexRequests.Api.Interfaces/IPushoverApi.cs b/PlexRequests.Api.Interfaces/IPushoverApi.cs index 42e3f2217..15f93f596 100644 --- a/PlexRequests.Api.Interfaces/IPushoverApi.cs +++ b/PlexRequests.Api.Interfaces/IPushoverApi.cs @@ -24,6 +24,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion +using System.Threading.Tasks; using PlexRequests.Api.Models.Notifications; @@ -31,6 +32,6 @@ namespace PlexRequests.Api.Interfaces { public interface IPushoverApi { - PushoverResponse Push(string accessToken, string message, string userToken); + Task PushAsync(string accessToken, string message, string userToken); } } \ No newline at end of file diff --git a/PlexRequests.Api/PushbulletApi.cs b/PlexRequests.Api/PushbulletApi.cs index 2c542348d..1e399e048 100644 --- a/PlexRequests.Api/PushbulletApi.cs +++ b/PlexRequests.Api/PushbulletApi.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion using System; +using System.Threading.Tasks; using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.Notifications; @@ -35,7 +36,7 @@ namespace PlexRequests.Api { public class PushbulletApi : IPushbulletApi { - public PushbulletResponse Push(string accessToken, string title, string message, string deviceIdentifier = default(string)) + public async Task PushAsync(string accessToken, string title, string message, string deviceIdentifier = default(string)) { var request = new RestRequest { @@ -56,7 +57,7 @@ namespace PlexRequests.Api request.AddJsonBody(push); var api = new ApiRequest(); - return api.ExecuteJson(request, new Uri("https://api.pushbullet.com/v2/pushes")); + return await Task.Run(() => api.ExecuteJson(request, new Uri("https://api.pushbullet.com/v2/pushes"))); } } } diff --git a/PlexRequests.Api/PushoverApi.cs b/PlexRequests.Api/PushoverApi.cs index 1de5694aa..6d109ca9b 100644 --- a/PlexRequests.Api/PushoverApi.cs +++ b/PlexRequests.Api/PushoverApi.cs @@ -25,7 +25,8 @@ // ************************************************************************/ #endregion using System; -using Nancy.Helpers; +using System.Threading.Tasks; + using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.Notifications; @@ -35,7 +36,7 @@ namespace PlexRequests.Api { public class PushoverApi : IPushoverApi { - public PushoverResponse Push(string accessToken, string message, string userToken) + public async Task PushAsync(string accessToken, string message, string userToken) { var request = new RestRequest { @@ -49,7 +50,7 @@ namespace PlexRequests.Api var api = new ApiRequest(); - return api.ExecuteJson(request, new Uri("https://api.pushover.net/1")); + return await Task.Run(() => api.ExecuteJson(request, new Uri("https://api.pushover.net/1"))); } } } diff --git a/PlexRequests.Services.Tests/NotificationServiceTests.cs b/PlexRequests.Services.Tests/NotificationServiceTests.cs index 877ddcbbf..940bcedda 100644 --- a/PlexRequests.Services.Tests/NotificationServiceTests.cs +++ b/PlexRequests.Services.Tests/NotificationServiceTests.cs @@ -1,33 +1,37 @@ #region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: NotificationServiceTests.cs -// Created By: Jamie Rees -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ************************************************************************/ +/************************************************************************ + Copyright (c) 2016 Jamie Rees + File: NotificationServiceTests.cs + Created By: Jamie Rees + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ************************************************************************/ #endregion +using System; +using System.Threading.Tasks; + using Moq; using NUnit.Framework; +using PlexRequests.Services.Interfaces; using PlexRequests.Services.Notification; namespace PlexRequests.Services.Tests @@ -35,9 +39,15 @@ namespace PlexRequests.Services.Tests [TestFixture] public class NotificationServiceTests { + public NotificationService NotificationService { get; set; } + + [SetUp] + public void Setup() + { + NotificationService = new NotificationService(); + } [Test] - [Ignore("Need to rework due to static class")] public void SubscribeNewNotifier() { var notificationMock = new Mock(); @@ -49,7 +59,6 @@ namespace PlexRequests.Services.Tests } [Test] - [Ignore("Need to rework due to static class")] public void SubscribeExistingNotifier() { var notificationMock1 = new Mock(); @@ -68,7 +77,6 @@ namespace PlexRequests.Services.Tests } [Test] - [Ignore("Need to rework due to static class")] public void UnSubscribeMissingNotifier() { var notificationMock = new Mock(); @@ -79,7 +87,6 @@ namespace PlexRequests.Services.Tests } [Test] - [Ignore("Need to rework due to static class")] public void UnSubscribeNotifier() { var notificationMock = new Mock(); @@ -92,17 +99,15 @@ namespace PlexRequests.Services.Tests } [Test] - [Ignore("Need to rework due to static class")] public void PublishWithNoObservers() { - Assert.DoesNotThrow( - () => - { NotificationService.Publish(new NotificationModel()); }); + Assert.DoesNotThrowAsync( + async() => + { await NotificationService.Publish(new NotificationModel()); }); } [Test] - [Ignore("Need to rework due to static class")] - public void PublishAllNotifiers() + public async Task PublishAllNotifiers() { var notificationMock1 = new Mock(); var notificationMock2 = new Mock(); @@ -112,11 +117,21 @@ namespace PlexRequests.Services.Tests NotificationService.Subscribe(notificationMock2.Object); Assert.That(NotificationService.Observers.Count, Is.EqualTo(2)); - var model = new NotificationModel {Title = "abc", Body = "test"}; - NotificationService.Publish(model); + var model = new NotificationModel { Title = "abc", Body = "test" }; + await NotificationService.Publish(model); + + notificationMock1.Verify(x => x.NotifyAsync(model), Times.Once); + notificationMock2.Verify(x => x.NotifyAsync(model), Times.Once); + } - notificationMock1.Verify(x => x.Notify(model), Times.Once); - notificationMock2.Verify(x => x.Notify(model), Times.Once); + [Test] + public async Task PublishWithException() + { + var notificationMock = new Mock(); + notificationMock.Setup(x => x.NotifyAsync(It.IsAny())).Throws(); + notificationMock.SetupGet(x => x.NotificationName).Returns("Notification1"); + NotificationService.Subscribe(notificationMock.Object); + await NotificationService.Publish(new NotificationModel()); } } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/INotification.cs b/PlexRequests.Services/Interfaces/INotification.cs similarity index 75% rename from PlexRequests.Services/Notification/INotification.cs rename to PlexRequests.Services/Interfaces/INotification.cs index dd099747d..14b09f0e9 100644 --- a/PlexRequests.Services/Notification/INotification.cs +++ b/PlexRequests.Services/Interfaces/INotification.cs @@ -24,22 +24,16 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion -namespace PlexRequests.Services.Notification +using System.Threading.Tasks; + +using PlexRequests.Services.Notification; + +namespace PlexRequests.Services.Interfaces { public interface INotification { - /// - /// Gets the name of the notification. - /// - /// - /// The name of the notification. - /// string NotificationName { get; } - /// - /// Notifies the specified title. - /// - /// The model. - /// - bool Notify(NotificationModel model); + + Task NotifyAsync(NotificationModel model); } } \ No newline at end of file diff --git a/PlexRequests.Services/Interfaces/INotificationService.cs b/PlexRequests.Services/Interfaces/INotificationService.cs new file mode 100644 index 000000000..59db3b509 --- /dev/null +++ b/PlexRequests.Services/Interfaces/INotificationService.cs @@ -0,0 +1,40 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: INotificationService.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using System.Threading.Tasks; + +using PlexRequests.Services.Notification; + +namespace PlexRequests.Services.Interfaces +{ + public interface INotificationService + { + Task Publish(NotificationModel model); + void Subscribe(INotification notification); + void UnSubscribe(INotification notification); + + } +} \ No newline at end of file diff --git a/PlexRequests.Services/Notification/EmailMessageNotification.cs b/PlexRequests.Services/Notification/EmailMessageNotification.cs index db6bc24b2..472b6a069 100644 --- a/PlexRequests.Services/Notification/EmailMessageNotification.cs +++ b/PlexRequests.Services/Notification/EmailMessageNotification.cs @@ -27,11 +27,13 @@ using System; using System.Net; using System.Net.Mail; +using System.Threading.Tasks; using NLog; using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; namespace PlexRequests.Services.Notification { @@ -47,31 +49,35 @@ namespace PlexRequests.Services.Notification private EmailNotificationSettings Settings => GetConfiguration(); public string NotificationName => "EmailMessageNotification"; - public bool Notify(NotificationModel model) + public async Task NotifyAsync(NotificationModel model) { var configuration = GetConfiguration(); if (!ValidateConfiguration(configuration)) { - return false; + return; } switch (model.NotificationType) { case NotificationType.NewRequest: - return EmailNewRequest(model); + await EmailNewRequest(model); + break; case NotificationType.Issue: - return EmailIssue(model); - case NotificationType.RequestAvailable: + await EmailIssue(model); break; + case NotificationType.RequestAvailable: + throw new NotImplementedException(); + case NotificationType.RequestApproved: - break; + throw new NotImplementedException(); + case NotificationType.AdminNote: - break; + throw new NotImplementedException(); + default: throw new ArgumentOutOfRangeException(); } - - return false; + } private EmailNotificationSettings GetConfiguration() @@ -94,7 +100,7 @@ namespace PlexRequests.Services.Notification return true; } - private bool EmailNewRequest(NotificationModel model) + private async Task EmailNewRequest(NotificationModel model) { var message = new MailMessage { @@ -111,22 +117,20 @@ namespace PlexRequests.Services.Notification { smtp.Credentials = new NetworkCredential(Settings.EmailUsername, Settings.EmailPassword); smtp.EnableSsl = Settings.Ssl; - smtp.Send(message); - return true; + await smtp.SendMailAsync(message).ConfigureAwait(false); } } catch (SmtpException smtp) { - Log.Fatal(smtp); + Log.Error(smtp); } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } - private bool EmailIssue(NotificationModel model) + private async Task EmailIssue(NotificationModel model) { var message = new MailMessage { @@ -143,19 +147,17 @@ namespace PlexRequests.Services.Notification { smtp.Credentials = new NetworkCredential(Settings.EmailUsername, Settings.EmailPassword); smtp.EnableSsl = Settings.Ssl; - smtp.Send(message); - return true; + await smtp.SendMailAsync(message).ConfigureAwait(false); } } catch (SmtpException smtp) { - Log.Fatal(smtp); + Log.Error(smtp); } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/NotificationService.cs b/PlexRequests.Services/Notification/NotificationService.cs index 817dcd2d9..116f5aef9 100644 --- a/PlexRequests.Services/Notification/NotificationService.cs +++ b/PlexRequests.Services/Notification/NotificationService.cs @@ -24,64 +24,49 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion -using System.Collections.Generic; -using System.Threading; +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading.Tasks; using NLog; -using PlexRequests.Helpers; +using PlexRequests.Services.Interfaces; namespace PlexRequests.Services.Notification { - public static class NotificationService + public class NotificationService : INotificationService { - private static Logger Log = LogManager.GetCurrentClassLogger(); - public static Dictionary Observers { get; } + public ConcurrentDictionary Observers { get; } = new ConcurrentDictionary(); - static NotificationService() + public async Task Publish(NotificationModel model) { - Observers = new Dictionary(); + var notificationTasks = Observers.Values.Select(notification => NotifyAsync(notification, model)); + + await Task.WhenAll(notificationTasks).ConfigureAwait(false); } - public static void Publish(NotificationModel model) + public void Subscribe(INotification notification) { - Log.Trace("Notifying all observers: "); - Log.Trace(Observers.DumpJson()); - foreach (var observer in Observers) - { - var notification = observer.Value; - - new Thread(() => - { - Thread.CurrentThread.IsBackground = true; - notification.Notify(model); - }).Start(); - } + Observers.TryAdd(notification.NotificationName, notification); } - public static void Subscribe(INotification notification) + public void UnSubscribe(INotification notification) { - INotification notificationValue; - if (Observers.TryGetValue(notification.NotificationName, out notificationValue)) - { - return; - } - - Observers[notification.NotificationName] = notification; + Observers.TryRemove(notification.NotificationName, out notification); } - public static void UnSubscribe(INotification notification) + private static async Task NotifyAsync(INotification notification, NotificationModel model) { - Log.Trace("Unsubscribing Observer {0}", notification.NotificationName); - INotification notificationValue; - if (!Observers.TryGetValue(notification.NotificationName, out notificationValue)) + try + { + await notification.NotifyAsync(model).ConfigureAwait(false); + } + catch (Exception ex) { - Log.Trace("Observer {0} doesn't exist to Unsubscribe", notification.NotificationName); - // Observer doesn't exists - return; + Log.Error(ex, $"Notification '{notification.NotificationName}' failed with exception"); } - Observers.Remove(notification.NotificationName); } } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/PushbulletNotification.cs b/PlexRequests.Services/Notification/PushbulletNotification.cs index 20c4b9f35..4e2f02144 100644 --- a/PlexRequests.Services/Notification/PushbulletNotification.cs +++ b/PlexRequests.Services/Notification/PushbulletNotification.cs @@ -25,12 +25,14 @@ // ************************************************************************/ #endregion using System; +using System.Threading.Tasks; using NLog; using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; namespace PlexRequests.Services.Notification { @@ -41,27 +43,27 @@ namespace PlexRequests.Services.Notification PushbulletApi = pushbulletApi; SettingsService = settings; } - private IPushbulletApi PushbulletApi { get; } + private IPushbulletApi PushbulletApi { get; } private ISettingsService SettingsService { get; } private PushbulletNotificationSettings Settings => GetSettings(); private static Logger Log = LogManager.GetCurrentClassLogger(); public string NotificationName => "PushbulletNotification"; - public bool Notify(NotificationModel model) + public async Task NotifyAsync(NotificationModel model) { if (!ValidateConfiguration()) { - return false; + return; } switch (model.NotificationType) { case NotificationType.NewRequest: - return PushNewRequest(model); - + await PushNewRequestAsync(model); + break; case NotificationType.Issue: - return PushIssue(model); - + await PushIssueAsync(model); + break; case NotificationType.RequestAvailable: break; case NotificationType.RequestApproved: @@ -71,8 +73,6 @@ namespace PlexRequests.Services.Notification default: throw new ArgumentOutOfRangeException(); } - return false; - } private bool ValidateConfiguration() @@ -93,42 +93,40 @@ namespace PlexRequests.Services.Notification return SettingsService.GetSettings(); } - private bool PushNewRequest(NotificationModel model) + private async Task PushNewRequestAsync(NotificationModel model) { var message = $"{model.Title} has been requested by user: {model.User}"; var pushTitle = $"Plex Requests: {model.Title} has been requested!"; try { - var result = PushbulletApi.Push(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier); - if (result != null) + var result = await PushbulletApi.PushAsync(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier); + if (result == null) { - return true; + Log.Error("Pushbullet api returned a null value, the notification did not get pushed"); } } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } - private bool PushIssue(NotificationModel model) + private async Task PushIssueAsync(NotificationModel model) { var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; var pushTitle = $"Plex Requests: A new issue has been reported for {model.Title}"; try { - var result = PushbulletApi.Push(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier); + var result = await PushbulletApi.PushAsync(Settings.AccessToken, pushTitle, message, Settings.DeviceIdentifier); if (result != null) { - return true; + Log.Error("Pushbullet api returned a null value, the notification did not get pushed"); } } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/PushoverNotification.cs b/PlexRequests.Services/Notification/PushoverNotification.cs index 2c3bf6bfe..bca0b2c90 100644 --- a/PlexRequests.Services/Notification/PushoverNotification.cs +++ b/PlexRequests.Services/Notification/PushoverNotification.cs @@ -25,12 +25,14 @@ // ************************************************************************/ #endregion using System; +using System.Threading.Tasks; using NLog; using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; namespace PlexRequests.Services.Notification { @@ -47,21 +49,21 @@ namespace PlexRequests.Services.Notification private static Logger Log = LogManager.GetCurrentClassLogger(); public string NotificationName => "PushoverNotification"; - public bool Notify(NotificationModel model) + public async Task NotifyAsync(NotificationModel model) { if (!ValidateConfiguration()) { - return false; + return; } switch (model.NotificationType) { case NotificationType.NewRequest: - return PushNewRequest(model); - + await PushNewRequestAsync(model); + break; case NotificationType.Issue: - return PushIssue(model); - + await PushIssueAsync(model); + break; case NotificationType.RequestAvailable: break; case NotificationType.RequestApproved: @@ -71,8 +73,6 @@ namespace PlexRequests.Services.Notification default: throw new ArgumentOutOfRangeException(); } - return false; - } private bool ValidateConfiguration() @@ -93,40 +93,38 @@ namespace PlexRequests.Services.Notification return SettingsService.GetSettings(); } - private bool PushNewRequest(NotificationModel model) + private async Task PushNewRequestAsync(NotificationModel model) { var message = $"Plex Requests: {model.Title} has been requested by user: {model.User}"; try { - var result = PushoverApi.Push(Settings.AccessToken, message, Settings.UserToken); - if (result?.status == 1) + var result = await PushoverApi.PushAsync(Settings.AccessToken, message, Settings.UserToken); + if (result?.status != 1) { - return true; + Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed"); } } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } - private bool PushIssue(NotificationModel model) + private async Task PushIssueAsync(NotificationModel model) { var message = $"Plex Requests: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; try { - var result = PushoverApi.Push(Settings.AccessToken, message, Settings.UserToken); - if (result != null) + var result = await PushoverApi.PushAsync(Settings.AccessToken, message, Settings.UserToken); + if (result?.status != 1) { - return true; + Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed"); } } catch (Exception e) { - Log.Fatal(e); + Log.Error(e); } - return false; } } } \ No newline at end of file diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj index e1ba81532..bbb334ca9 100644 --- a/PlexRequests.Services/PlexRequests.Services.csproj +++ b/PlexRequests.Services/PlexRequests.Services.csproj @@ -77,7 +77,8 @@ - + + diff --git a/PlexRequests.UI.Tests/AdminModuleTests.cs b/PlexRequests.UI.Tests/AdminModuleTests.cs index 137e49d0b..fc8686086 100644 --- a/PlexRequests.UI.Tests/AdminModuleTests.cs +++ b/PlexRequests.UI.Tests/AdminModuleTests.cs @@ -39,6 +39,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.Plex; using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; using PlexRequests.Store.Models; using PlexRequests.Store.Repository; using PlexRequests.UI.Models; @@ -64,6 +65,7 @@ namespace PlexRequests.UI.Tests private Mock PushoverApi { get; set; } private Mock CpApi { get; set; } private Mock> LogRepo { get; set; } + private Mock NotificationService { get; set; } private ConfigurableBootstrapper Bootstrapper { get; set; } @@ -91,6 +93,7 @@ namespace PlexRequests.UI.Tests LogRepo = new Mock>(); PushoverSettings = new Mock>(); PushoverApi = new Mock(); + NotificationService = new Mock(); Bootstrapper = new ConfigurableBootstrapper(with => { @@ -110,6 +113,7 @@ namespace PlexRequests.UI.Tests with.Dependency(LogRepo.Object); with.Dependency(PushoverSettings.Object); with.Dependency(PushoverApi.Object); + with.Dependency(NotificationService.Object); with.RootPathProvider(); with.RequestStartup((container, pipelines, context) => { diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index 46d68c797..5e4f24343 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -96,6 +96,9 @@ namespace PlexRequests.UI container.Register(); container.Register(); + // NotificationService + container.Register().AsSingleton(); + SubscribeAllObservers(container); base.ConfigureRequestContainer(container, context); } @@ -130,25 +133,27 @@ namespace PlexRequests.UI private void SubscribeAllObservers(TinyIoCContainer container) { + var notificationService = container.Resolve(); + var emailSettingsService = container.Resolve>(); var emailSettings = emailSettingsService.GetSettings(); if (emailSettings.Enabled) { - NotificationService.Subscribe(new EmailMessageNotification(emailSettingsService)); + notificationService.Subscribe(new EmailMessageNotification(emailSettingsService)); } var pushbulletService = container.Resolve>(); var pushbulletSettings = pushbulletService.GetSettings(); if (pushbulletSettings.Enabled) { - NotificationService.Subscribe(new PushbulletNotification(container.Resolve(), pushbulletService)); + notificationService.Subscribe(new PushbulletNotification(container.Resolve(), pushbulletService)); } var pushoverService = container.Resolve>(); var pushoverSettings = pushoverService.GetSettings(); if (pushoverSettings.Enabled) { - NotificationService.Subscribe(new PushoverNotification(container.Resolve(), pushoverService)); + notificationService.Subscribe(new PushoverNotification(container.Resolve(), pushoverService)); } } } diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index be0d14e05..2ff454f9b 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -26,7 +26,6 @@ #endregion using System.Dynamic; using System.Linq; -using System.Web.UI.WebControls; using MarkdownSharp; @@ -44,6 +43,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; +using PlexRequests.Services.Interfaces; using PlexRequests.Services.Notification; using PlexRequests.Store.Models; using PlexRequests.Store.Repository; @@ -69,6 +69,7 @@ namespace PlexRequests.UI.Modules private IPushoverApi PushoverApi { get; } private ICouchPotatoApi CpApi { get; } private IRepository LogsRepo { get; } + private INotificationService NotificationService { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); public AdminModule(ISettingsService rpService, @@ -85,7 +86,8 @@ namespace PlexRequests.UI.Modules ICouchPotatoApi cpApi, ISettingsService pushoverSettings, IPushoverApi pushoverApi, - IRepository logsRepo) : base("admin") + IRepository logsRepo, + INotificationService notify) : base("admin") { RpService = rpService; CpService = cpService; @@ -102,6 +104,7 @@ namespace PlexRequests.UI.Modules LogsRepo = logsRepo; PushoverService = pushoverSettings; PushoverApi = pushoverApi; + NotificationService = notify; #if !DEBUG this.RequiresAuthentication(); diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs index 228a0d752..2f9eb364d 100644 --- a/PlexRequests.UI/Modules/RequestsModule.cs +++ b/PlexRequests.UI/Modules/RequestsModule.cs @@ -26,7 +26,6 @@ #endregion using System; -using System.Collections.Generic; using System.Linq; using Humanizer; @@ -35,9 +34,9 @@ using Nancy; using Nancy.Responses.Negotiation; using Nancy.Security; -using PlexRequests.Api; using PlexRequests.Core; using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; using PlexRequests.Services.Notification; using PlexRequests.Store; using PlexRequests.UI.Models; @@ -47,11 +46,12 @@ namespace PlexRequests.UI.Modules public class RequestsModule : BaseModule { - public RequestsModule(IRequestService service, ISettingsService prSettings, ISettingsService plex) : base("requests") + public RequestsModule(IRequestService service, ISettingsService prSettings, ISettingsService plex, INotificationService notify) : base("requests") { Service = service; PrSettings = prSettings; PlexSettings = plex; + NotificationService = notify; Get["/"] = _ => LoadRequests(); Get["/movies"] = _ => GetMovies(); @@ -67,6 +67,7 @@ namespace PlexRequests.UI.Modules } private IRequestService Service { get; } + private INotificationService NotificationService { get; } private ISettingsService PrSettings { get; } private ISettingsService PlexSettings { get; } diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 5fce72960..5e29f15e9 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -53,7 +53,8 @@ namespace PlexRequests.UI.Modules public SearchModule(ICacheProvider cache, ISettingsService cpSettings, ISettingsService prSettings, IAvailabilityChecker checker, IRequestService request, ISonarrApi sonarrApi, ISettingsService sonarrSettings, - ISettingsService sickRageService, ICouchPotatoApi cpApi, ISickRageApi srApi) : base("search") + ISettingsService sickRageService, ICouchPotatoApi cpApi, ISickRageApi srApi, + INotificationService notify) : base("search") { CpService = cpSettings; PrService = prSettings; @@ -67,6 +68,7 @@ namespace PlexRequests.UI.Modules CouchPotatoApi = cpApi; SickRageService = sickRageService; SickrageApi = srApi; + NotificationService = notify; Get["/"] = parameters => RequestLoad(); @@ -80,6 +82,7 @@ namespace PlexRequests.UI.Modules Post["request/tv"] = parameters => RequestTvShow((int)Request.Form.tvId, (bool)Request.Form.latest); } private TheMovieDbApi MovieApi { get; } + private INotificationService NotificationService { get; } private ICouchPotatoApi CouchPotatoApi { get; } private ISonarrApi SonarrApi { get; } private TheTvDbApi TvApi { get; }