From 2d5612a045a62dca1670da45e51aabf7623bf5ec Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 22 Mar 2016 22:17:06 +0000 Subject: [PATCH] Finished adding pushover support. #44 --- PlexRequests.Api.Interfaces/IPushoverApi.cs | 36 +++++ .../PlexRequests.Api.Interfaces.csproj | 1 + .../Notifications/PushoverResponse.cs | 34 +++++ .../PlexRequests.Api.Models.csproj | 1 + PlexRequests.Api/PlexRequests.Api.csproj | 1 + PlexRequests.Api/PushoverApi.cs | 56 ++++++++ PlexRequests.Core/PlexRequests.Core.csproj | 1 + .../PushoverNotificationSettings.cs | 9 ++ .../Notification/PushoverNotification.cs | 132 ++++++++++++++++++ .../PlexRequests.Services.csproj | 1 + PlexRequests.UI.Tests/AdminModuleTests.cs | 6 + PlexRequests.UI/Bootstrapper.cs | 11 +- PlexRequests.UI/Modules/AdminModule.cs | 45 +++++- PlexRequests.UI/PlexRequests.UI.csproj | 4 + .../Validators/PushoverSettingsValidator.cs | 41 ++++++ .../Views/Admin/PushoverNotifications.cshtml | 74 ++++++++++ PlexRequests.UI/Views/Admin/_Sidebar.cshtml | 9 ++ 17 files changed, 459 insertions(+), 3 deletions(-) create mode 100644 PlexRequests.Api.Interfaces/IPushoverApi.cs create mode 100644 PlexRequests.Api.Models/Notifications/PushoverResponse.cs create mode 100644 PlexRequests.Api/PushoverApi.cs create mode 100644 PlexRequests.Core/SettingModels/PushoverNotificationSettings.cs create mode 100644 PlexRequests.Services/Notification/PushoverNotification.cs create mode 100644 PlexRequests.UI/Validators/PushoverSettingsValidator.cs create mode 100644 PlexRequests.UI/Views/Admin/PushoverNotifications.cshtml diff --git a/PlexRequests.Api.Interfaces/IPushoverApi.cs b/PlexRequests.Api.Interfaces/IPushoverApi.cs new file mode 100644 index 000000000..42e3f2217 --- /dev/null +++ b/PlexRequests.Api.Interfaces/IPushoverApi.cs @@ -0,0 +1,36 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: IPushoverApi.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 PlexRequests.Api.Models.Notifications; + +namespace PlexRequests.Api.Interfaces +{ + public interface IPushoverApi + { + PushoverResponse Push(string accessToken, string message, string userToken); + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj b/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj index 3ea7be621..7522c8156 100644 --- a/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj +++ b/PlexRequests.Api.Interfaces/PlexRequests.Api.Interfaces.csproj @@ -49,6 +49,7 @@ + diff --git a/PlexRequests.Api.Models/Notifications/PushoverResponse.cs b/PlexRequests.Api.Models/Notifications/PushoverResponse.cs new file mode 100644 index 000000000..94849fba1 --- /dev/null +++ b/PlexRequests.Api.Models/Notifications/PushoverResponse.cs @@ -0,0 +1,34 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PushoverResponse.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 +namespace PlexRequests.Api.Models.Notifications +{ + public class PushoverResponse + { + public int status { get; set; } + public string request { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj index bd3151c55..8a4da4222 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -50,6 +50,7 @@ + diff --git a/PlexRequests.Api/PlexRequests.Api.csproj b/PlexRequests.Api/PlexRequests.Api.csproj index 2f204c975..6422dfd6f 100644 --- a/PlexRequests.Api/PlexRequests.Api.csproj +++ b/PlexRequests.Api/PlexRequests.Api.csproj @@ -72,6 +72,7 @@ MockApiData.resx + diff --git a/PlexRequests.Api/PushoverApi.cs b/PlexRequests.Api/PushoverApi.cs new file mode 100644 index 000000000..1de5694aa --- /dev/null +++ b/PlexRequests.Api/PushoverApi.cs @@ -0,0 +1,56 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PlexApi.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 Nancy.Helpers; +using PlexRequests.Api.Interfaces; +using PlexRequests.Api.Models.Notifications; + +using RestSharp; + +namespace PlexRequests.Api +{ + public class PushoverApi : IPushoverApi + { + public PushoverResponse Push(string accessToken, string message, string userToken) + { + var request = new RestRequest + { + Method = Method.POST, + Resource = "messages.json?token={token}&user={user}&message={message}" + }; + + request.AddUrlSegment("token", accessToken); + request.AddUrlSegment("message", message); + request.AddUrlSegment("user", userToken); + + + var api = new ApiRequest(); + return api.ExecuteJson(request, new Uri("https://api.pushover.net/1")); + } + } +} + diff --git a/PlexRequests.Core/PlexRequests.Core.csproj b/PlexRequests.Core/PlexRequests.Core.csproj index e1c4ee1f3..9b698ab96 100644 --- a/PlexRequests.Core/PlexRequests.Core.csproj +++ b/PlexRequests.Core/PlexRequests.Core.csproj @@ -73,6 +73,7 @@ + diff --git a/PlexRequests.Core/SettingModels/PushoverNotificationSettings.cs b/PlexRequests.Core/SettingModels/PushoverNotificationSettings.cs new file mode 100644 index 000000000..ac6c4c435 --- /dev/null +++ b/PlexRequests.Core/SettingModels/PushoverNotificationSettings.cs @@ -0,0 +1,9 @@ +namespace PlexRequests.Core.SettingModels +{ + public class PushoverNotificationSettings : Settings + { + public bool Enabled { get; set; } + public string AccessToken { get; set; } + public string UserToken { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/Notification/PushoverNotification.cs b/PlexRequests.Services/Notification/PushoverNotification.cs new file mode 100644 index 000000000..2c3bf6bfe --- /dev/null +++ b/PlexRequests.Services/Notification/PushoverNotification.cs @@ -0,0 +1,132 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PushbulletNotification.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 NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; + +namespace PlexRequests.Services.Notification +{ + public class PushoverNotification : INotification + { + public PushoverNotification(IPushoverApi pushoverApi, ISettingsService settings) + { + PushoverApi = pushoverApi; + SettingsService = settings; + } + private IPushoverApi PushoverApi { get; } + private ISettingsService SettingsService { get; } + private PushoverNotificationSettings Settings => GetSettings(); + + private static Logger Log = LogManager.GetCurrentClassLogger(); + public string NotificationName => "PushoverNotification"; + public bool Notify(NotificationModel model) + { + if (!ValidateConfiguration()) + { + return false; + } + + switch (model.NotificationType) + { + case NotificationType.NewRequest: + return PushNewRequest(model); + + case NotificationType.Issue: + return PushIssue(model); + + case NotificationType.RequestAvailable: + break; + case NotificationType.RequestApproved: + break; + case NotificationType.AdminNote: + break; + default: + throw new ArgumentOutOfRangeException(); + } + return false; + + } + + private bool ValidateConfiguration() + { + if (!Settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(Settings.AccessToken) || string.IsNullOrEmpty(Settings.UserToken)) + { + return false; + } + return true; + } + + private PushoverNotificationSettings GetSettings() + { + return SettingsService.GetSettings(); + } + + private bool PushNewRequest(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) + { + return true; + } + } + catch (Exception e) + { + Log.Fatal(e); + } + return false; + } + + private bool PushIssue(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) + { + return true; + } + } + catch (Exception e) + { + Log.Fatal(e); + } + return false; + } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj index 0317cf36b..e1ba81532 100644 --- a/PlexRequests.Services/PlexRequests.Services.csproj +++ b/PlexRequests.Services/PlexRequests.Services.csproj @@ -82,6 +82,7 @@ + diff --git a/PlexRequests.UI.Tests/AdminModuleTests.cs b/PlexRequests.UI.Tests/AdminModuleTests.cs index e42eb4a13..08c84235b 100644 --- a/PlexRequests.UI.Tests/AdminModuleTests.cs +++ b/PlexRequests.UI.Tests/AdminModuleTests.cs @@ -55,9 +55,11 @@ namespace PlexRequests.UI.Tests private Mock> SickRageSettingsMock { get; set; } private Mock> EmailMock { get; set; } private Mock> PushbulletSettings { get; set; } + private Mock> PushoverSettings { get; set; } private Mock PlexMock { get; set; } private Mock SonarrApiMock { get; set; } private Mock PushbulletApi { get; set; } + private Mock PushoverApi { get; set; } private Mock CpApi { get; set; } private ConfigurableBootstrapper Bootstrapper { get; set; } @@ -83,6 +85,8 @@ namespace PlexRequests.UI.Tests PushbulletSettings = new Mock>(); CpApi = new Mock(); SickRageSettingsMock = new Mock>(); + PushoverSettings = new Mock>(); + PushoverApi = new Mock(); Bootstrapper = new ConfigurableBootstrapper(with => { @@ -99,6 +103,8 @@ namespace PlexRequests.UI.Tests with.Dependency(PushbulletSettings.Object); with.Dependency(CpApi.Object); with.Dependency(SickRageSettingsMock.Object); + with.Dependency(PushoverSettings.Object); + with.Dependency(PushoverApi.Object); with.RootPathProvider(); with.RequestStartup((container, pipelines, context) => { diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index 8fd5aad2b..9c07266e9 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -74,6 +74,7 @@ namespace PlexRequests.UI container.Register, SettingsServiceV2>(); container.Register, SettingsServiceV2>(); container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); // Repo's container.Register, GenericRepository>(); @@ -88,6 +89,7 @@ namespace PlexRequests.UI // Api's container.Register(); container.Register(); + container.Register(); container.Register(); container.Register(); container.Register(); @@ -137,7 +139,14 @@ namespace PlexRequests.UI var pushbulletSettings = pushbulletService.GetSettings(); if (pushbulletSettings.Enabled) { - NotificationService.Subscribe(new PushbulletNotification(container.Resolve(), container.Resolve>())); + 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)); } } } diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index 7876aa41c..d97d06129 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -59,9 +59,11 @@ namespace PlexRequests.UI.Modules private ISettingsService SickRageService { get; } private ISettingsService EmailService { get; } private ISettingsService PushbulletService { get; } + private ISettingsService PushoverService { get; } private IPlexApi PlexApi { get; } private ISonarrApi SonarrApi { get; } - private PushbulletApi PushbulletApi { get; } + private IPushbulletApi PushbulletApi { get; } + private IPushoverApi PushoverApi { get; } private ICouchPotatoApi CpApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); @@ -76,7 +78,9 @@ namespace PlexRequests.UI.Modules IPlexApi plexApi, ISettingsService pbSettings, PushbulletApi pbApi, - ICouchPotatoApi cpApi) : base("admin") + ICouchPotatoApi cpApi, + ISettingsService pushoverSettings, + IPushoverApi pushoverApi) : base("admin") { RpService = rpService; CpService = cpService; @@ -90,6 +94,8 @@ namespace PlexRequests.UI.Modules PushbulletApi = pbApi; CpApi = cpApi; SickRageService = sickrage; + PushoverService = pushoverSettings; + PushoverApi = pushoverApi; #if !DEBUG this.RequiresAuthentication(); @@ -126,6 +132,9 @@ namespace PlexRequests.UI.Modules Get["/pushbulletnotification"] = _ => PushbulletNotifications(); Post["/pushbulletnotification"] = _ => SavePushbulletNotifications(); + + Get["/pushovernotification"] = _ => PushoverNotifications(); + Post["/pushovernotification"] = _ => SavePushoverNotifications(); } private Negotiator Authentication() @@ -415,6 +424,38 @@ namespace PlexRequests.UI.Modules : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } + private Negotiator PushoverNotifications() + { + var settings = PushoverService.GetSettings(); + return View["PushoverNotifications", settings]; + } + + private Response SavePushoverNotifications() + { + var settings = this.Bind(); + var valid = this.Validate(settings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + Log.Trace(settings.DumpJson()); + + var result = PushoverService.SaveSettings(settings); + if (settings.Enabled) + { + NotificationService.Subscribe(new PushoverNotification(PushoverApi, PushoverService)); + } + else + { + NotificationService.UnSubscribe(new PushoverNotification(PushoverApi, PushoverService)); + } + + Log.Info("Saved email settings, result: {0}", result); + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Pushbullet Notifications!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); + } + private Response GetCpProfiles() { var settings = this.Bind(); diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 44ec9805c..a62ab2592 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -166,6 +166,7 @@ + @@ -335,6 +336,9 @@ Always + + Always + web.config diff --git a/PlexRequests.UI/Validators/PushoverSettingsValidator.cs b/PlexRequests.UI/Validators/PushoverSettingsValidator.cs new file mode 100644 index 000000000..55a218aa0 --- /dev/null +++ b/PlexRequests.UI/Validators/PushoverSettingsValidator.cs @@ -0,0 +1,41 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrValidator.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 FluentValidation; + +using PlexRequests.Core.SettingModels; + +namespace PlexRequests.UI.Validators +{ + public class PushoverSettingsValidator : AbstractValidator + { + public PushoverSettingsValidator() + { + RuleFor(request => request.AccessToken).NotEmpty().WithMessage("You must specify a API Token."); + RuleFor(request => request.UserToken).NotEmpty().WithMessage("You must specify a User Token."); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/PushoverNotifications.cshtml b/PlexRequests.UI/Views/Admin/PushoverNotifications.cshtml new file mode 100644 index 000000000..0877739d0 --- /dev/null +++ b/PlexRequests.UI/Views/Admin/PushoverNotifications.cshtml @@ -0,0 +1,74 @@ +@Html.Partial("_Sidebar") + +
+
+
+ Pushover Notifications + +
+
+ +
+
+ +
+ + Enter your API Key from Pushover. +
+ +
+
+ +
+ + Your user or group key from Pushover. +
+ +
+
+ +
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/_Sidebar.cshtml b/PlexRequests.UI/Views/Admin/_Sidebar.cshtml index 2877729c7..51e181921 100644 --- a/PlexRequests.UI/Views/Admin/_Sidebar.cshtml +++ b/PlexRequests.UI/Views/Admin/_Sidebar.cshtml @@ -71,6 +71,15 @@ Pushbullet Notifications } + @if (Context.Request.Path == "/admin/pushovernotification") + { + Pushover Notifications + } + else + { + Pushover Notifications + } + @if (Context.Request.Path == "/admin/status") { Status