From b287c8655fecdafb18fd3331486d0ad9e3f2a97d Mon Sep 17 00:00:00 2001 From: anonaut Date: Mon, 13 Mar 2017 23:43:42 +0100 Subject: [PATCH 1/5] Implemented mattermost notifications based on slack notification --- Ombi.Api.Interfaces/IMattermostApi.cs | 37 +++++ .../Ombi.Api.Interfaces.csproj | 1 + .../MattermostNotificationBody.cs | 54 ++++++ Ombi.Api.Models/Ombi.Api.Models.csproj | 1 + Ombi.Api/MattermostApi.cs | 58 +++++++ Ombi.Api/Ombi.Api.csproj | 1 + .../NotificationMessageResolver.cs | 3 + Ombi.Core/Notification/TransportType.cs | 3 +- Ombi.Core/Ombi.Core.csproj | 1 + .../MattermostNotificationSettings.cs | 12 ++ .../SettingModels/NotificationSettingsV2.cs | 2 + .../Notification/MattermostNotification.cs | 156 ++++++++++++++++++ Ombi.Services/Ombi.Services.csproj | 1 + Ombi.UI.Tests/AdminModuleTests.cs | 6 + Ombi.UI/Modules/Admin/AdminModule.cs | 76 ++++++++- Ombi.UI/NinjectModules/ApiModule.cs | 1 + Ombi.UI/Ombi.UI.csproj | 4 + Ombi.UI/Startup.cs | 4 + .../Validators/MattermostSettingsValidator.cs | 40 +++++ .../Admin/MattermostNotifications.cshtml | 119 +++++++++++++ Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml | 1 + 21 files changed, 579 insertions(+), 2 deletions(-) create mode 100644 Ombi.Api.Interfaces/IMattermostApi.cs create mode 100644 Ombi.Api.Models/Notifications/MattermostNotificationBody.cs create mode 100644 Ombi.Api/MattermostApi.cs create mode 100644 Ombi.Core/SettingModels/MattermostNotificationSettings.cs create mode 100644 Ombi.Services/Notification/MattermostNotification.cs create mode 100644 Ombi.UI/Validators/MattermostSettingsValidator.cs create mode 100644 Ombi.UI/Views/Admin/MattermostNotifications.cshtml diff --git a/Ombi.Api.Interfaces/IMattermostApi.cs b/Ombi.Api.Interfaces/IMattermostApi.cs new file mode 100644 index 000000000..e7db46b75 --- /dev/null +++ b/Ombi.Api.Interfaces/IMattermostApi.cs @@ -0,0 +1,37 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: IMattermostApi.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 Ombi.Api.Models.Notifications; + +namespace Ombi.Api.Interfaces +{ + public interface IMattermostApi + { + Task PushAsync(string webhook, MattermostNotificationBody message); + } +} \ No newline at end of file diff --git a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj index c8c1ca938..3d6e285bf 100644 --- a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj +++ b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj @@ -63,6 +63,7 @@ + diff --git a/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs new file mode 100644 index 000000000..a179019cd --- /dev/null +++ b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs @@ -0,0 +1,54 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: MattermostNotificationBody.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 Newtonsoft.Json; + +namespace Ombi.Api.Models.Notifications +{ + public class MattermostNotificationBody + { + [JsonConstructor] + public MattermostNotificationBody() + { + username = "Ombi"; + } + + [JsonIgnore] + private string _username; + public string username + { + get { return _username; } + set + { + if (!string.IsNullOrEmpty(value)) + _username = value; + } + } + public string channel { get; set; } + public string text { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Ombi.Api.Models.csproj b/Ombi.Api.Models/Ombi.Api.Models.csproj index 39df12460..92e4447ba 100644 --- a/Ombi.Api.Models/Ombi.Api.Models.csproj +++ b/Ombi.Api.Models/Ombi.Api.Models.csproj @@ -69,6 +69,7 @@ + diff --git a/Ombi.Api/MattermostApi.cs b/Ombi.Api/MattermostApi.cs new file mode 100644 index 000000000..c777e824b --- /dev/null +++ b/Ombi.Api/MattermostApi.cs @@ -0,0 +1,58 @@ +#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 System.Threading.Tasks; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Notifications; +using RestSharp; + +namespace Ombi.Api +{ + public class MattermostApi : IMattermostApi + { + public async Task PushAsync(string webhook, MattermostNotificationBody message) + { + var request = new RestRequest + { + Method = Method.POST, + Resource = "/" + }; + + request.AddJsonBody(message); + + var api = new ApiRequest(); + return await Task.Run( + () => + { + var result = api.Execute(request, new Uri(webhook)); + return result.Content; + }); + } + } +} + diff --git a/Ombi.Api/Ombi.Api.csproj b/Ombi.Api/Ombi.Api.csproj index b9e674cc2..ba4a0e7ec 100644 --- a/Ombi.Api/Ombi.Api.csproj +++ b/Ombi.Api/Ombi.Api.csproj @@ -80,6 +80,7 @@ + diff --git a/Ombi.Core/Notification/NotificationMessageResolver.cs b/Ombi.Core/Notification/NotificationMessageResolver.cs index f5f0b90f9..fee5eeb00 100644 --- a/Ombi.Core/Notification/NotificationMessageResolver.cs +++ b/Ombi.Core/Notification/NotificationMessageResolver.cs @@ -70,6 +70,9 @@ namespace Ombi.Core.Notification case TransportType.Slack: content = notification.SlackNotification; break; + case TransportType.Mattermost: + content = notification.MattermostNotification; + break; default: throw new ArgumentOutOfRangeException(nameof(transportType), transportType, null); } diff --git a/Ombi.Core/Notification/TransportType.cs b/Ombi.Core/Notification/TransportType.cs index f37ab4404..fbed9b3b0 100644 --- a/Ombi.Core/Notification/TransportType.cs +++ b/Ombi.Core/Notification/TransportType.cs @@ -31,6 +31,7 @@ namespace Ombi.Core.Notification Email, Pushbullet, Pushover, - Slack + Slack, + Mattermost } } \ No newline at end of file diff --git a/Ombi.Core/Ombi.Core.csproj b/Ombi.Core/Ombi.Core.csproj index f3f05b9da..747921e79 100644 --- a/Ombi.Core/Ombi.Core.csproj +++ b/Ombi.Core/Ombi.Core.csproj @@ -135,6 +135,7 @@ + diff --git a/Ombi.Core/SettingModels/MattermostNotificationSettings.cs b/Ombi.Core/SettingModels/MattermostNotificationSettings.cs new file mode 100644 index 000000000..3ae1eeb8b --- /dev/null +++ b/Ombi.Core/SettingModels/MattermostNotificationSettings.cs @@ -0,0 +1,12 @@ +using System; +using Newtonsoft.Json; + +namespace Ombi.Core.SettingModels +{ + public sealed class MattermostNotificationSettings : NotificationSettings + { + public string WebhookUrl { get; set; } + public string Channel { get; set; } + public string Username { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Core/SettingModels/NotificationSettingsV2.cs b/Ombi.Core/SettingModels/NotificationSettingsV2.cs index 2380d70f1..cf0209692 100644 --- a/Ombi.Core/SettingModels/NotificationSettingsV2.cs +++ b/Ombi.Core/SettingModels/NotificationSettingsV2.cs @@ -51,11 +51,13 @@ namespace Ombi.Core.SettingModels } }; SlackNotification = new List(); + MattermostNotification = new List(); PushoverNotification = new List(); PushbulletNotification = new List(); } public List EmailNotification { get; set; } public List SlackNotification { get; set; } + public List MattermostNotification { get; set; } public List PushbulletNotification { get; set; } public List PushoverNotification { get; set; } } diff --git a/Ombi.Services/Notification/MattermostNotification.cs b/Ombi.Services/Notification/MattermostNotification.cs new file mode 100644 index 000000000..9d8cdbaf9 --- /dev/null +++ b/Ombi.Services/Notification/MattermostNotification.cs @@ -0,0 +1,156 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: MattermostNotification.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 NLog; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Notifications; +using Ombi.Core; +using Ombi.Core.Models; +using Ombi.Core.SettingModels; +using Ombi.Services.Interfaces; + +namespace Ombi.Services.Notification +{ + public class MattermostNotification : INotification + { + public MattermostNotification(IMattermostApi api, ISettingsService sn) + { + Api = api; + Settings = sn; + } + + public string NotificationName => "MattermostNotification"; + + private IMattermostApi Api { get; } + private ISettingsService Settings { get; } + private static Logger Log = LogManager.GetCurrentClassLogger(); + + + public async Task NotifyAsync(NotificationModel model) + { + var settings = Settings.GetSettings(); + + await NotifyAsync(model, settings); + } + + public async Task NotifyAsync(NotificationModel model, Settings settings) + { + if (settings == null) await NotifyAsync(model); + + var pushSettings = (MattermostNotificationSettings)settings; + if (!ValidateConfiguration(pushSettings)) + { + Log.Error("Settings for Mattermost was not correct, we cannot push a notification"); + return; + } + + switch (model.NotificationType) + { + case NotificationType.NewRequest: + await PushNewRequestAsync(model, pushSettings); + break; + case NotificationType.Issue: + await PushIssueAsync(model, pushSettings); + break; + case NotificationType.RequestAvailable: + break; + case NotificationType.RequestApproved: + break; + case NotificationType.AdminNote: + break; + case NotificationType.Test: + await PushTest(pushSettings); + break; + case NotificationType.RequestDeclined: + break; + case NotificationType.ItemAddedToFaultQueue: + await PushFaultQueue(model, pushSettings); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private async Task PushNewRequestAsync(NotificationModel model, MattermostNotificationSettings settings) + { + var message = $"{model.Title} has been requested by user: {model.User}"; + await Push(settings, message); + } + + private async Task PushIssueAsync(NotificationModel model, MattermostNotificationSettings settings) + { + var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; + await Push(settings, message); + } + + private async Task PushTest(MattermostNotificationSettings settings) + { + var message = $"This is a test from Ombi, if you can see this then we have successfully pushed a notification!"; + await Push(settings, message); + } + + private async Task PushFaultQueue(NotificationModel model, MattermostNotificationSettings settings) + { + var message = $"Hello! The user '{model.User}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying"; + await Push(settings, message); + } + + private async Task Push(MattermostNotificationSettings config, string message) + { + try + { + var notification = new MattermostNotificationBody { username = config.Username, channel = config.Channel ?? string.Empty, text = message }; + + var result = await Api.PushAsync(config.WebhookUrl, notification); + if (!result.Equals("ok")) + { + Log.Error("Mattermost returned a message that was not 'ok', the notification did not get pushed"); + Log.Error($"Message that mattermost returned: {result}"); + } + } + catch (Exception e) + { + Log.Error(e); + } + } + + private bool ValidateConfiguration(MattermostNotificationSettings settings) + { + if (!settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(settings.WebhookUrl)) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Ombi.Services/Ombi.Services.csproj b/Ombi.Services/Ombi.Services.csproj index 6705cf939..d59173d7d 100644 --- a/Ombi.Services/Ombi.Services.csproj +++ b/Ombi.Services/Ombi.Services.csproj @@ -136,6 +136,7 @@ + diff --git a/Ombi.UI.Tests/AdminModuleTests.cs b/Ombi.UI.Tests/AdminModuleTests.cs index 62e4bf514..c612f92de 100644 --- a/Ombi.UI.Tests/AdminModuleTests.cs +++ b/Ombi.UI.Tests/AdminModuleTests.cs @@ -72,8 +72,10 @@ namespace Ombi.UI.Tests private Mock Cache { get; set; } private Mock> Log { get; set; } private Mock> SlackSettings { get; set; } + private Mock> MattermostSettings { get; set; } private Mock> LandingPageSettings { get; set; } private Mock SlackApi { get; set; } + private Mock MattermostApi { get; set; } private Mock Analytics { get; set; } private Mock> NotifyV2 { get; set; } private Mock RecentlyAdded { get; set; } @@ -113,6 +115,8 @@ namespace Ombi.UI.Tests Log = new Mock>(); SlackApi = new Mock(); SlackSettings = new Mock>(); + MattermostApi = new Mock(); + MattermostSettings = new Mock>(); LandingPageSettings = new Mock>(); ScheduledJobsSettingsMock = new Mock>(); RecorderMock = new Mock(); @@ -146,8 +150,10 @@ namespace Ombi.UI.Tests with.Dependency(Cache.Object); with.Dependency(Log.Object); with.Dependency(SlackApi.Object); + with.Dependency(MattermostApi.Object); with.Dependency(LandingPageSettings.Object); with.Dependency(SlackSettings.Object); + with.Dependency(MattermostSettings.Object); with.Dependency(ScheduledJobsSettingsMock.Object); with.Dependency(RecorderMock.Object); with.Dependency(RecentlyAdded.Object); diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index 97a610441..8fd242769 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -86,9 +86,11 @@ namespace Ombi.UI.Modules.Admin private INotificationService NotificationService { get; } private ICacheProvider Cache { get; } private ISettingsService SlackSettings { get; } + private ISettingsService MattermostSettings { get; } private ISettingsService LandingSettings { get; } private ISettingsService ScheduledJobSettings { get; } private ISlackApi SlackApi { get; } + private IMattermostApi MattermostApi { get; } private IJobRecord JobRecorder { get; } private IAnalytics Analytics { get; } private IRecentlyAdded RecentlyAdded { get; } @@ -119,7 +121,8 @@ namespace Ombi.UI.Modules.Admin ISettingsService headphones, ISettingsService logs, ICacheProvider cache, ISettingsService slackSettings, - ISlackApi slackApi, ISettingsService lp, + ISlackApi slackApi, ISettingsService mattermostSettings, + IMattermostApi mattermostApi, ISettingsService lp, ISettingsService scheduler, IJobRecord rec, IAnalytics analytics, ISettingsService notifyService, IRecentlyAdded recentlyAdded, ISettingsService watcherSettings , @@ -149,6 +152,8 @@ namespace Ombi.UI.Modules.Admin Cache = cache; SlackSettings = slackSettings; SlackApi = slackApi; + MattermostSettings = mattermostSettings; + MattermostApi = mattermostApi; LandingSettings = lp; ScheduledJobSettings = scheduler; JobRecorder = rec; @@ -222,6 +227,10 @@ namespace Ombi.UI.Modules.Admin Get["/slacknotification"] = _ => SlackNotifications(); Post["/slacknotification"] = _ => SaveSlackNotifications(); + Post["/testmattermostnotification", true] = async (x, ct) => await TestMattermostNotification(); + Get["/mattermostnotification"] = _ => MattermostNotifications(); + Post["/mattermostnotification"] = _ => SaveMattermostNotifications(); + Post["/testdiscordnotification", true] = async (x, ct) => await TestDiscordNotification(); Get["/discordnotification", true] = async (x, ct) => await DiscordNotification(); Post["/discordnotification", true] = async (x, ct) => await SaveDiscordNotifications(); @@ -957,6 +966,71 @@ namespace Ombi.UI.Modules.Admin : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } + private async Task TestMattermostNotification() + { + var settings = this.BindAndValidate(); + if (!ModelValidationResult.IsValid) + { + return Response.AsJson(ModelValidationResult.SendJsonError()); + } + var notificationModel = new NotificationModel + { + NotificationType = NotificationType.Test, + DateTime = DateTime.Now + }; + + var currentMattermostSettings = await MattermostSettings.GetSettingsAsync(); + try + { + NotificationService.Subscribe(new MattermostNotification(MattermostApi, MattermostSettings)); + settings.Enabled = true; + await NotificationService.Publish(notificationModel, settings); + Log.Info("Sent mattermost notification test"); + } + catch (Exception e) + { + Log.Error(e, "Failed to subscribe and publish test Mattermost Notification"); + } + finally + { + if (!currentMattermostSettings.Enabled) + { + NotificationService.UnSubscribe(new MattermostNotification(MattermostApi, MattermostSettings)); + } + } + return Response.AsJson(new JsonResponseModel { Result = true, Message = "Successfully sent a test Mattermost Notification! If you do not receive it please check the logs." }); + } + + private Negotiator MattermostNotifications() + { + var settings = MattermostSettings.GetSettings(); + return View["MattermostNotifications", settings]; + } + + private Response SaveMattermostNotifications() + { + var settings = this.BindAndValidate(); + if (!ModelValidationResult.IsValid) + { + return Response.AsJson(ModelValidationResult.SendJsonError()); + } + + var result = MattermostSettings.SaveSettings(settings); + if (settings.Enabled) + { + NotificationService.Subscribe(new MattermostNotification(MattermostApi, MattermostSettings)); + } + else + { + NotificationService.UnSubscribe(new MattermostNotification(MattermostApi, MattermostSettings)); + } + + Log.Info("Saved mattermost settings, result: {0}", result); + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Mattermost Notifications!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); + } + private async Task DiscordNotification() { var settings = await DiscordSettings.GetSettingsAsync(); diff --git a/Ombi.UI/NinjectModules/ApiModule.cs b/Ombi.UI/NinjectModules/ApiModule.cs index 1a45764c7..39291e84d 100644 --- a/Ombi.UI/NinjectModules/ApiModule.cs +++ b/Ombi.UI/NinjectModules/ApiModule.cs @@ -44,6 +44,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); Bind().To(); Bind().To(); Bind().To(); diff --git a/Ombi.UI/Ombi.UI.csproj b/Ombi.UI/Ombi.UI.csproj index 24fa57f52..f080929d5 100644 --- a/Ombi.UI/Ombi.UI.csproj +++ b/Ombi.UI/Ombi.UI.csproj @@ -298,6 +298,7 @@ + @@ -737,6 +738,9 @@ Always + + Always + Always diff --git a/Ombi.UI/Startup.cs b/Ombi.UI/Startup.cs index ff8590da4..85da67a1a 100644 --- a/Ombi.UI/Startup.cs +++ b/Ombi.UI/Startup.cs @@ -125,6 +125,10 @@ namespace Ombi.UI var slackSettings = slackService.GetSettings(); SubScribeOvserver(slackSettings, notificationService, new SlackNotification(container.Get(), slackService)); + var mattermostService = container.Get>(); + var mattermostSettings = mattermostService.GetSettings(); + SubScribeOvserver(mattermostSettings, notificationService, new MattermostNotification(container.Get(), mattermostService)); + var discordSettings = container.Get>(); var discordService = discordSettings.GetSettings(); SubScribeOvserver(discordService, notificationService, new DiscordNotification(container.Get(), discordSettings)); diff --git a/Ombi.UI/Validators/MattermostSettingsValidator.cs b/Ombi.UI/Validators/MattermostSettingsValidator.cs new file mode 100644 index 000000000..d6c34c434 --- /dev/null +++ b/Ombi.UI/Validators/MattermostSettingsValidator.cs @@ -0,0 +1,40 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: MattermostSettingsValidator.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 Ombi.Core.SettingModels; + +namespace Ombi.UI.Validators +{ + public class MattermostSettingsValidator : AbstractValidator + { + public MattermostSettingsValidator() + { + RuleFor(request => request.WebhookUrl).NotEmpty().WithMessage("You must specify a Webhook Url"); + } + } +} \ No newline at end of file diff --git a/Ombi.UI/Views/Admin/MattermostNotifications.cshtml b/Ombi.UI/Views/Admin/MattermostNotifications.cshtml new file mode 100644 index 000000000..10d04e7c1 --- /dev/null +++ b/Ombi.UI/Views/Admin/MattermostNotifications.cshtml @@ -0,0 +1,119 @@ +@using Ombi.UI.Helpers +@Html.Partial("Shared/Partial/_Sidebar") + +
+
+
+ Mattermost Notifications + +
+
+ + @if (Model.Enabled) + { + + } + else + { + + } + +
+
+ +
+ + This is the full webhook url. + Mattermost > Settings > Add app or integration > Build > Make a Custom Integration > Incoming Webhooks > Add Incoming Webhook. You will then have a Webhook Url +
+ +
+
+ +
+ + You can override the default channel here +
+ +
+
+ +
+ + You can override the default username (Ombi) here +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml index e62947012..a4f609549 100644 --- a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml +++ b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml @@ -31,6 +31,7 @@ @Html.GetSidebarUrl(Context, "/admin/pushbulletnotification", "Pushbullet Notifications","fa fa-bell-o") @Html.GetSidebarUrl(Context, "/admin/pushovernotification", "Pushover Notifications", "fa fa-bell-o") @Html.GetSidebarUrl(Context, "/admin/slacknotification", "Slack Notifications", "fa fa-slack") + @Html.GetSidebarUrl(Context, "/admin/mattermostnotification", "Mattermost Notifications", "fa fa-bell-o") @Html.GetSidebarUrl(Context, "/admin/discordnotification", "Discord Notifications", "fa fa-bell-o") From 2f1060b665c0ffbde559158411bce7b380e18b86 Mon Sep 17 00:00:00 2001 From: anonaut Date: Tue, 14 Mar 2017 00:15:26 +0100 Subject: [PATCH 2/5] Added icon_url functionality to mattermost notification --- .../Notifications/MattermostNotificationBody.cs | 1 + .../SettingModels/MattermostNotificationSettings.cs | 1 + Ombi.Services/Notification/MattermostNotification.cs | 2 +- Ombi.UI/Views/Admin/MattermostNotifications.cshtml | 10 +++++++++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs index a179019cd..b804352e0 100644 --- a/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs +++ b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs @@ -50,5 +50,6 @@ namespace Ombi.Api.Models.Notifications } public string channel { get; set; } public string text { get; set; } + public string icon_url { get; set; } } } \ No newline at end of file diff --git a/Ombi.Core/SettingModels/MattermostNotificationSettings.cs b/Ombi.Core/SettingModels/MattermostNotificationSettings.cs index 3ae1eeb8b..03ae5af3e 100644 --- a/Ombi.Core/SettingModels/MattermostNotificationSettings.cs +++ b/Ombi.Core/SettingModels/MattermostNotificationSettings.cs @@ -8,5 +8,6 @@ namespace Ombi.Core.SettingModels public string WebhookUrl { get; set; } public string Channel { get; set; } public string Username { get; set; } + public string IconUrl { get; set; } } } \ No newline at end of file diff --git a/Ombi.Services/Notification/MattermostNotification.cs b/Ombi.Services/Notification/MattermostNotification.cs index 9d8cdbaf9..708e8df34 100644 --- a/Ombi.Services/Notification/MattermostNotification.cs +++ b/Ombi.Services/Notification/MattermostNotification.cs @@ -125,7 +125,7 @@ namespace Ombi.Services.Notification { try { - var notification = new MattermostNotificationBody { username = config.Username, channel = config.Channel ?? string.Empty, text = message }; + var notification = new MattermostNotificationBody { username = config.Username, channel = config.Channel ?? string.Empty, icon_url = config.IconUrl ?? string.Empty, text = message }; var result = await Api.PushAsync(config.WebhookUrl, notification); if (!result.Equals("ok")) diff --git a/Ombi.UI/Views/Admin/MattermostNotifications.cshtml b/Ombi.UI/Views/Admin/MattermostNotifications.cshtml index 10d04e7c1..b48256319 100644 --- a/Ombi.UI/Views/Admin/MattermostNotifications.cshtml +++ b/Ombi.UI/Views/Admin/MattermostNotifications.cshtml @@ -24,7 +24,7 @@
This is the full webhook url. - Mattermost > Settings > Add app or integration > Build > Make a Custom Integration > Incoming Webhooks > Add Incoming Webhook. You will then have a Webhook Url + Mattermost > Integrations > Incoming Webhook > Add Incoming Webhook. You will then have a Webhook Url
@@ -46,6 +46,14 @@
+
+ + You can override the default icon here +
+ +
+
+
From 235337e7c9419799f46027b5833e6787bd2f7cab Mon Sep 17 00:00:00 2001 From: Patrick Frisch Date: Mon, 10 Apr 2017 15:48:55 +0200 Subject: [PATCH 3/5] fixed author and rewrote getter/setter method --- Ombi.Api.Interfaces/IMattermostApi.cs | 2 +- .../Notifications/MattermostNotificationBody.cs | 14 ++------------ Ombi.Api/MattermostApi.cs | 2 +- .../Notification/MattermostNotification.cs | 2 +- Ombi.UI/Validators/MattermostSettingsValidator.cs | 2 +- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Ombi.Api.Interfaces/IMattermostApi.cs b/Ombi.Api.Interfaces/IMattermostApi.cs index e7db46b75..281902277 100644 --- a/Ombi.Api.Interfaces/IMattermostApi.cs +++ b/Ombi.Api.Interfaces/IMattermostApi.cs @@ -2,7 +2,7 @@ // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: IMattermostApi.cs -// Created By: Jamie Rees +// Created By: Michel Zaleski // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs index b804352e0..0c5b17685 100644 --- a/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs +++ b/Ombi.Api.Models/Notifications/MattermostNotificationBody.cs @@ -2,7 +2,7 @@ // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: MattermostNotificationBody.cs -// Created By: Jamie Rees +// Created By: Michel Zaleski // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -37,17 +37,7 @@ namespace Ombi.Api.Models.Notifications username = "Ombi"; } - [JsonIgnore] - private string _username; - public string username - { - get { return _username; } - set - { - if (!string.IsNullOrEmpty(value)) - _username = value; - } - } + public string username { get; set; } = "Ombi"; public string channel { get; set; } public string text { get; set; } public string icon_url { get; set; } diff --git a/Ombi.Api/MattermostApi.cs b/Ombi.Api/MattermostApi.cs index c777e824b..9edbef7b6 100644 --- a/Ombi.Api/MattermostApi.cs +++ b/Ombi.Api/MattermostApi.cs @@ -2,7 +2,7 @@ // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: PlexApi.cs -// Created By: Jamie Rees +// Created By: Michel Zaleski // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/Ombi.Services/Notification/MattermostNotification.cs b/Ombi.Services/Notification/MattermostNotification.cs index 708e8df34..671974bf5 100644 --- a/Ombi.Services/Notification/MattermostNotification.cs +++ b/Ombi.Services/Notification/MattermostNotification.cs @@ -2,7 +2,7 @@ // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: MattermostNotification.cs -// Created By: Jamie Rees +// Created By: Michel Zaleski // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the diff --git a/Ombi.UI/Validators/MattermostSettingsValidator.cs b/Ombi.UI/Validators/MattermostSettingsValidator.cs index d6c34c434..333762d79 100644 --- a/Ombi.UI/Validators/MattermostSettingsValidator.cs +++ b/Ombi.UI/Validators/MattermostSettingsValidator.cs @@ -2,7 +2,7 @@ // /************************************************************************ // Copyright (c) 2016 Jamie Rees // File: MattermostSettingsValidator.cs -// Created By: Jamie Rees +// Created By: Michel Zaleski // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the From dffc0f3d7575483c672110244f9588ddb9baa2d1 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Wed, 12 Apr 2017 08:21:17 +0100 Subject: [PATCH 4/5] Fixed an issue where some users couldn't update thier plex admin account. looks like their user id changed in plex. We now update the main user. #1249 --- Ombi.Services/Jobs/PlexUserChecker.cs | 14 +++++++++++++- Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Ombi.Services/Jobs/PlexUserChecker.cs b/Ombi.Services/Jobs/PlexUserChecker.cs index 1ea679b02..4e888c72e 100644 --- a/Ombi.Services/Jobs/PlexUserChecker.cs +++ b/Ombi.Services/Jobs/PlexUserChecker.cs @@ -190,10 +190,22 @@ namespace Ombi.Services.Jobs LoginId = Guid.NewGuid().ToString() }; - a.Permissions += (int)Permissions.Administrator; // Make admin + a.Permissions += (int) Permissions.Administrator; // Make admin Repo.Insert(a); } + else + { + // does the account need updating? + if (dbMainAcc != null) + { + dbMainAcc.PlexUserId = mainPlexAccount.Id; + dbMainAcc.EmailAddress = mainPlexAccount.Email; + dbMainAcc.Username = mainPlexAccount.Username; + + Repo.Update(dbMainAcc); + } + } } diff --git a/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs b/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs index 083eb57d9..c8d40d081 100644 --- a/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs +++ b/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs @@ -152,7 +152,7 @@ namespace Ombi.UI.Modules.Admin } if (key.Equals(JobNames.PlexUserChecker, StringComparison.CurrentCultureIgnoreCase)) { - RequestLimit.Start(); + PlexUserChecker.Start(); } if (key.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase)) { From deb5878405feede15c04d646b9f0f6e786b15496 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Wed, 12 Apr 2017 08:24:52 +0100 Subject: [PATCH 5/5] Fixed the issue where we mark as unavailable and a declined notification gets triggered #1371 --- Ombi.UI/Modules/RequestsModule.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Ombi.UI/Modules/RequestsModule.cs b/Ombi.UI/Modules/RequestsModule.cs index 8fc65c515..b1222be9b 100644 --- a/Ombi.UI/Modules/RequestsModule.cs +++ b/Ombi.UI/Modules/RequestsModule.cs @@ -526,18 +526,21 @@ namespace Ombi.UI.Modules var result = await Service.UpdateRequestAsync(originalRequest); var plexSettings = await PlexSettings.GetSettingsAsync(); - if (plexSettings.Enable) + if (available) { - await - PlexNotificationEngine.NotifyUsers(originalRequest, - available ? NotificationType.RequestAvailable : NotificationType.RequestDeclined); - } + if (plexSettings.Enable) + { + await + PlexNotificationEngine.NotifyUsers(originalRequest, + NotificationType.RequestAvailable); + } - var embySettings = await EmbySettings.GetSettingsAsync(); - if (embySettings.Enable) - { - await EmbyNotificationEngine.NotifyUsers(originalRequest, - available ? NotificationType.RequestAvailable : NotificationType.RequestDeclined); + var embySettings = await EmbySettings.GetSettingsAsync(); + if (embySettings.Enable) + { + await EmbyNotificationEngine.NotifyUsers(originalRequest, + NotificationType.RequestAvailable); + } } return Response.AsJson(result ? new { Result = true, Available = available, Message = string.Empty }