From cdc002ecd73c1ac939c009981b0b96d6ac9dc157 Mon Sep 17 00:00:00 2001 From: Namaneo Date: Fri, 29 Nov 2019 16:05:14 +0100 Subject: [PATCH] Add webhook notification and API logic --- src/Ombi.Api.Webhook/IWebhookApi.cs | 10 ++ src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj | 15 +++ src/Ombi.Api.Webhook/WebhookApi.cs | 36 ++++++ .../Models/UI/WebhookNotificationViewModel.cs | 15 +++ .../Agents/Interfaces/IWebhookNotification.cs | 6 + .../Agents/WebhookNotification.cs | 116 ++++++++++++++++++ .../Models/Notifications/WebhookSettings.cs | 9 ++ src/Ombi.sln | 11 +- 8 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 src/Ombi.Api.Webhook/IWebhookApi.cs create mode 100644 src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj create mode 100644 src/Ombi.Api.Webhook/WebhookApi.cs create mode 100644 src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs create mode 100644 src/Ombi.Notifications/Agents/Interfaces/IWebhookNotification.cs create mode 100644 src/Ombi.Notifications/Agents/WebhookNotification.cs create mode 100644 src/Ombi.Settings/Settings/Models/Notifications/WebhookSettings.cs diff --git a/src/Ombi.Api.Webhook/IWebhookApi.cs b/src/Ombi.Api.Webhook/IWebhookApi.cs new file mode 100644 index 000000000..755c7c789 --- /dev/null +++ b/src/Ombi.Api.Webhook/IWebhookApi.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Ombi.Api.Webhook +{ + public interface IWebhookApi + { + Task PushAsync(string endpoint, string accessToken, IReadOnlyDictionary parameters); + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj b/src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj new file mode 100644 index 000000000..321c1f333 --- /dev/null +++ b/src/Ombi.Api.Webhook/Ombi.Api.Webhook.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + 3.0.0.0 + 3.0.0.0 + + + + + + + + + \ No newline at end of file diff --git a/src/Ombi.Api.Webhook/WebhookApi.cs b/src/Ombi.Api.Webhook/WebhookApi.cs new file mode 100644 index 000000000..509de2622 --- /dev/null +++ b/src/Ombi.Api.Webhook/WebhookApi.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json.Serialization; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Ombi.Api.Webhook +{ + public class WebhookApi : IWebhookApi + { + private static readonly CamelCasePropertyNamesContractResolver _nameResolver = new CamelCasePropertyNamesContractResolver(); + + public WebhookApi(IApi api) + { + _api = api; + } + + private readonly IApi _api; + + public async Task PushAsync(string baseUrl, string accessToken, IReadOnlyDictionary parameters) + { + var request = new Request("/", baseUrl, HttpMethod.Post); + request.AddHeader("Access-Token", accessToken); + request.ApplicationJsonContentType(); + + var body = parameters.ToDictionary( + x => _nameResolver.GetResolvedPropertyName(x.Key), + x => x.Value + ); + + request.AddJsonBody(body); + + await _api.Request(request); + } + } +} diff --git a/src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs b/src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs new file mode 100644 index 000000000..533de1d6b --- /dev/null +++ b/src/Ombi.Core/Models/UI/WebhookNotificationViewModel.cs @@ -0,0 +1,15 @@ + +using System.Collections.Generic; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; + +namespace Ombi.Core.Models.UI +{ + /// + /// The view model for the notification settings page + /// + /// + public class WebhookNotificationViewModel : WebhookSettings + { + } +} diff --git a/src/Ombi.Notifications/Agents/Interfaces/IWebhookNotification.cs b/src/Ombi.Notifications/Agents/Interfaces/IWebhookNotification.cs new file mode 100644 index 000000000..303229878 --- /dev/null +++ b/src/Ombi.Notifications/Agents/Interfaces/IWebhookNotification.cs @@ -0,0 +1,6 @@ +namespace Ombi.Notifications.Agents +{ + public interface IWebhookNotification : INotification + { + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/WebhookNotification.cs b/src/Ombi.Notifications/Agents/WebhookNotification.cs new file mode 100644 index 000000000..fbbb1d352 --- /dev/null +++ b/src/Ombi.Notifications/Agents/WebhookNotification.cs @@ -0,0 +1,116 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.Webhook; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Notifications.Models; +using Ombi.Settings.Settings.Models; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; +using Ombi.Store.Repository; +using Ombi.Store.Repository.Requests; + +namespace Ombi.Notifications.Agents +{ + public class WebhookNotification : BaseNotification, IWebhookNotification + { + public WebhookNotification(IWebhookApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, + ISettingsService s, IRepository sub, IMusicRequestRepository music, + IRepository userPref) : base(sn, r, m, t, s, log, sub, music, userPref) + { + Api = api; + Logger = log; + } + + public override string NotificationName => "WebhookNotification"; + + private IWebhookApi Api { get; } + private ILogger Logger { get; } + + protected override bool ValidateConfiguration(WebhookSettings settings) + { + return settings.Enabled && !string.IsNullOrEmpty(settings.WebhookUrl); + } + + protected override async Task NewRequest(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.NewRequest); + } + + + protected override async Task NewIssue(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.Issue); + } + + protected override async Task IssueComment(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.IssueComment); + } + + protected override async Task IssueResolved(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.IssueResolved); + } + + protected override async Task AddedToRequestQueue(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.ItemAddedToFaultQueue); + } + + protected override async Task RequestDeclined(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.RequestDeclined); + } + + protected override async Task RequestApproved(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.RequestApproved); + } + + protected override async Task AvailableRequest(NotificationOptions model, WebhookSettings settings) + { + await Run(model, settings, NotificationType.RequestAvailable); + } + + protected override async Task Send(NotificationMessage model, WebhookSettings settings) + { + try + { + await Api.PushAsync(settings.WebhookUrl, settings.ApplicationToken, model.Data); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.WebhookNotification, e, "Failed to send webhook notification"); + } + } + + protected override async Task Test(NotificationOptions model, WebhookSettings settings) + { + var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!"; + var notification = new NotificationMessage + { + Message = message, + }; + await Send(notification, settings); + } + + private async Task Run(NotificationOptions model, WebhookSettings settings, NotificationType type) + { + var parsed = await LoadTemplate(NotificationAgent.Webhook, type, model); + if (parsed.Disabled) + { + Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Webhook}"); + return; + } + + var notification = new NotificationMessage + { + Data = parsed.Data, + }; + + await Send(notification, settings); + } + } +} diff --git a/src/Ombi.Settings/Settings/Models/Notifications/WebhookSettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/WebhookSettings.cs new file mode 100644 index 000000000..1c304e84c --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/Notifications/WebhookSettings.cs @@ -0,0 +1,9 @@ +namespace Ombi.Settings.Settings.Models.Notifications +{ + public class WebhookSettings : Settings + { + public bool Enabled { get; set; } + public string WebhookUrl { get; set; } + public string ApplicationToken { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.sln b/src/Ombi.sln index f4f683c11..e71c1a30c 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29519.87 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi", "Ombi\Ombi.csproj", "{C987AA67-AFE1-468F-ACD3-EAD5A48E1F6A}" EndProject @@ -100,6 +100,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers.Tests", "Ombi. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Gotify", "Ombi.Api.Gotify\Ombi.Api.Gotify.csproj", "{105EA346-766E-45B8-928B-DE6991DCB7EB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Webhook", "Ombi.Api.Webhook\Ombi.Api.Webhook.csproj", "{E2186FDA-D827-4781-8663-130AC382F12C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -262,6 +264,10 @@ Global {105EA346-766E-45B8-928B-DE6991DCB7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {105EA346-766E-45B8-928B-DE6991DCB7EB}.Release|Any CPU.Build.0 = Release|Any CPU + {E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2186FDA-D827-4781-8663-130AC382F12C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2186FDA-D827-4781-8663-130AC382F12C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2186FDA-D827-4781-8663-130AC382F12C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -300,6 +306,7 @@ Global {4FA21A20-92F4-462C-B929-2C517A88CC56} = {9293CA11-360A-4C20-A674-B9E794431BF5} {CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3} = {6F42AB98-9196-44C4-B888-D5E409F415A1} {105EA346-766E-45B8-928B-DE6991DCB7EB} = {9293CA11-360A-4C20-A674-B9E794431BF5} + {E2186FDA-D827-4781-8663-130AC382F12C} = {9293CA11-360A-4C20-A674-B9E794431BF5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869}