From fa76a57f08bcf32f3d515fedf7eb3608042f3acc Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 13 Mar 2019 20:59:39 +0000 Subject: [PATCH 01/20] Fixed a migration issue --- src/Ombi/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ombi/Program.cs b/src/Ombi/Program.cs index 40fd37e73..f1809a2dc 100644 --- a/src/Ombi/Program.cs +++ b/src/Ombi/Program.cs @@ -115,7 +115,7 @@ namespace Ombi try { - if (ombi.Settings.Any()) + if (ombi.Settings.Any() && !settings.Settings.Any()) { // OK migrate it! var allSettings = ombi.Settings.ToList(); @@ -125,7 +125,7 @@ namespace Ombi // Check for any application settings - if (ombi.ApplicationConfigurations.Any()) + if (ombi.ApplicationConfigurations.Any() && !settings.ApplicationConfigurations.Any()) { // OK migrate it! var allSettings = ombi.ApplicationConfigurations.ToList(); From 1322076aa678207b424f2cc92a4394ba7f187e17 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Mon, 11 Mar 2019 08:33:16 +0000 Subject: [PATCH 02/20] Added a global mutex (not used yet) and moved around the code for loggin in since I suspect the Get Roles call is using deffered execution on the database causing the lock when attempting to access straight away #2750 --- src/Ombi.Helpers/GlobalMutex.cs | 38 +++++++++++++++++++++++++ src/Ombi/Controllers/TokenController.cs | 6 ++-- 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/Ombi.Helpers/GlobalMutex.cs diff --git a/src/Ombi.Helpers/GlobalMutex.cs b/src/Ombi.Helpers/GlobalMutex.cs new file mode 100644 index 000000000..ecf9cdf15 --- /dev/null +++ b/src/Ombi.Helpers/GlobalMutex.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading; + +namespace Ombi.Helpers +{ + public static class GlobalMutex + { + public static T Lock(Func func) + { + const string mutexId = "Global\\OMBI"; + + using (var mutex = new Mutex(false, mutexId, out __)) + { + var hasHandle = false; + try + { + try + { + hasHandle = mutex.WaitOne(5000, false); + if (hasHandle == false) + throw new TimeoutException("Timeout waiting for exclusive access"); + } + catch (AbandonedMutexException) + { + hasHandle = true; + } + + return func(); + } + finally + { + if (hasHandle) + mutex.ReleaseMutex(); + } + } + } + } +} diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index 44ec5686f..b27c04caa 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -123,9 +123,6 @@ namespace Ombi.Controllers return new UnauthorizedResult(); } - user.LastLoggedIn = DateTime.UtcNow; - await _userManager.UpdateAsync(user); - var claims = new List { new Claim(JwtRegisteredClaimNames.Sub, user.UserName), @@ -152,6 +149,9 @@ namespace Ombi.Controllers //await _token.CreateToken(new Tokens() {Token = accessToken, User = user}); } + user.LastLoggedIn = DateTime.UtcNow; + await _userManager.UpdateAsync(user); + return new JsonResult(new { access_token = accessToken, From 947c0e74cbe7bb2b471261d3d52a4e6dbdb8e079 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Thu, 14 Mar 2019 11:12:28 +0000 Subject: [PATCH 03/20] Made use of the global mutex, this should now hopefully work #2750 --- src/Ombi.Helpers/GlobalMutex.cs | 9 +++++---- src/Ombi.Store/Repository/BaseRepository.cs | 14 +++++--------- src/Ombi/Controllers/TokenController.cs | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Ombi.Helpers/GlobalMutex.cs b/src/Ombi.Helpers/GlobalMutex.cs index ecf9cdf15..0164e888c 100644 --- a/src/Ombi.Helpers/GlobalMutex.cs +++ b/src/Ombi.Helpers/GlobalMutex.cs @@ -1,15 +1,16 @@ using System; using System.Threading; +using System.Threading.Tasks; +using Nito.AsyncEx; namespace Ombi.Helpers { public static class GlobalMutex { - public static T Lock(Func func) + public static async Task Lock(Func> func) { const string mutexId = "Global\\OMBI"; - - using (var mutex = new Mutex(false, mutexId, out __)) + using (var mutex = new Mutex(false, mutexId, out _)) { var hasHandle = false; try @@ -25,7 +26,7 @@ namespace Ombi.Helpers hasHandle = true; } - return func(); + return await func(); } finally { diff --git a/src/Ombi.Store/Repository/BaseRepository.cs b/src/Ombi.Store/Repository/BaseRepository.cs index 21dd2dac5..ca2937291 100644 --- a/src/Ombi.Store/Repository/BaseRepository.cs +++ b/src/Ombi.Store/Repository/BaseRepository.cs @@ -5,7 +5,7 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; -using Nito.AsyncEx; +using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities; @@ -20,7 +20,6 @@ namespace Ombi.Store.Repository } public DbSet _db { get; } private readonly U _ctx; - private readonly AsyncLock _mutex = new AsyncLock(); public async Task Find(object key) { @@ -32,7 +31,7 @@ namespace Ombi.Store.Repository return _db.AsQueryable(); } - public async Task FirstOrDefaultAsync(Expression> predicate) + public async Task FirstOrDefaultAsync(Expression> predicate) { return await _db.FirstOrDefaultAsync(predicate); } @@ -84,12 +83,9 @@ namespace Ombi.Store.Repository private async Task InternalSaveChanges() { - using (await _mutex.LockAsync()) - { - return await _ctx.SaveChangesAsync(); - } + return await GlobalMutex.Lock(async () => await _ctx.SaveChangesAsync()); } - + private bool _disposed; // Protected implementation of Dispose pattern. @@ -102,7 +98,7 @@ namespace Ombi.Store.Repository { _ctx?.Dispose(); } - + _disposed = true; } diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index b27c04caa..9499dd493 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -150,7 +150,7 @@ namespace Ombi.Controllers } user.LastLoggedIn = DateTime.UtcNow; - await _userManager.UpdateAsync(user); + await GlobalMutex.Lock(async () => await _userManager.UpdateAsync(user)).ConfigureAwait(false); return new JsonResult(new { From 2b1eebafd106acb975f1ade74f5a52c6c95f7a83 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Thu, 14 Mar 2019 13:52:17 +0000 Subject: [PATCH 04/20] Set the View On Emby Url at runtime so the user can configure and change the URL and it will take effect straight away --- .../Rule/Rules/Search/EmbyAvailabilityRule.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs index 3171c6ada..f80bded7a 100644 --- a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Store.Entities; using Ombi.Store.Repository; @@ -11,12 +13,14 @@ namespace Ombi.Core.Rule.Rules.Search { public class EmbyAvailabilityRule : BaseSearchRule, IRules { - public EmbyAvailabilityRule(IEmbyContentRepository repo) + public EmbyAvailabilityRule(IEmbyContentRepository repo, ISettingsService s) { EmbyContentRepository = repo; + EmbySettings = s; } private IEmbyContentRepository EmbyContentRepository { get; } + private ISettingsService EmbySettings { get; } public async Task Execute(SearchViewModel obj) { @@ -60,7 +64,16 @@ namespace Ombi.Core.Rule.Rules.Search if (item != null) { obj.Available = true; - obj.EmbyUrl = item.Url; + var s = await EmbySettings.GetSettingsAsync(); + var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null); + if ((server?.ServerHostname ?? string.Empty).HasValue()) + { + obj.EmbyUrl = $"{server.ServerHostname}#!/itemdetails.html?id={item.EmbyId}"; + } + else + { + obj.EmbyUrl = $"https://app.emby.media/#!/itemdetails.html?id={item.EmbyId}"; + } if (obj.Type == RequestType.TvShow) { From f048505eed7d14fbd4f159ec593c5c125e276de9 Mon Sep 17 00:00:00 2001 From: TidusJar Date: Thu, 14 Mar 2019 20:58:04 +0000 Subject: [PATCH 05/20] Fixed #2636 --- src/Ombi.Notifications/GenericEmailProvider.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Ombi.Notifications/GenericEmailProvider.cs b/src/Ombi.Notifications/GenericEmailProvider.cs index 462f8918e..e255c4357 100644 --- a/src/Ombi.Notifications/GenericEmailProvider.cs +++ b/src/Ombi.Notifications/GenericEmailProvider.cs @@ -4,7 +4,9 @@ using EnsureThat; using MailKit.Net.Smtp; using Microsoft.Extensions.Logging; using MimeKit; +using MimeKit.Utils; using Ombi.Core.Settings; +using Ombi.Helpers; using Ombi.Notifications.Models; using Ombi.Notifications.Templates; using Ombi.Settings.Settings.Models; @@ -36,6 +38,15 @@ namespace Ombi.Notifications var customization = await CustomizationSettings.GetSettingsAsync(); var html = email.LoadTemplate(model.Subject, model.Message, null, customization.Logo); + + var messageId = MimeUtils.GenerateMessageId(); + if (customization.ApplicationUrl.HasValue()) + { + if (Uri.TryCreate(customization.ApplicationUrl, UriKind.RelativeOrAbsolute, out var url)) + { + messageId = MimeUtils.GenerateMessageId(url.IdnHost); + } + } var textBody = string.Empty; @@ -49,7 +60,8 @@ namespace Ombi.Notifications var message = new MimeMessage { Body = body.ToMessageBody(), - Subject = model.Subject + Subject = model.Subject, + MessageId = messageId }; message.From.Add(new MailboxAddress(string.IsNullOrEmpty(settings.SenderName) ? settings.SenderAddress : settings.SenderName, settings.SenderAddress)); message.To.Add(new MailboxAddress(model.To, model.To)); From 52b75ee4de1ebab4d7d85236e0c75ba8a00756f9 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 18 Mar 2019 12:46:47 +0000 Subject: [PATCH 06/20] Update JobSetup.cs --- src/Ombi.Schedule/JobSetup.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index 5cc818441..38686396f 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -81,7 +81,6 @@ namespace Ombi.Schedule RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s)); RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s)); RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s)); - RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s)); RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s)); RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s)); } From 94b70c2f2cff1675b07f158065f7203425023e55 Mon Sep 17 00:00:00 2001 From: Guillaume Taquet Gasperini Date: Wed, 20 Mar 2019 19:40:37 +0100 Subject: [PATCH 07/20] Add Gotify as notification provider --- README.md | 1 + src/Ombi.Api.Gotify/GotifyApi.cs | 36 ++++++ src/Ombi.Api.Gotify/IGotifyApi.cs | 9 ++ src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj | 15 +++ .../Models/UI/GotifyNotificationViewModel.cs | 23 ++++ src/Ombi.DependencyInjection/IocExtensions.cs | 3 + src/Ombi.Helpers/LoggingEvents.cs | 1 + src/Ombi.Helpers/NotificationAgent.cs | 1 + src/Ombi.Mapping/Profiles/SettingsProfile.cs | 1 + .../Agents/GotifyNotification.cs | 116 ++++++++++++++++++ .../Agents/Interfaces/IGotifyNotification.cs | 6 + .../Ombi.Notifications.csproj | 1 + .../Models/Notifications/GotifySettings.cs | 10 ++ src/Ombi.sln | 9 +- .../app/interfaces/INotificationSettings.ts | 8 ++ .../services/applications/tester.service.ts | 7 +- .../app/services/settings.service.ts | 9 ++ .../notifications/gotify.component.html | 67 ++++++++++ .../notifications/gotify.component.ts | 68 ++++++++++ .../ClientApp/app/settings/settings.module.ts | 3 + .../app/settings/settingsmenu.component.html | 1 + .../Controllers/External/TesterController.cs | 28 ++++- src/Ombi/Controllers/SettingsController.cs | 34 +++++ 23 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 src/Ombi.Api.Gotify/GotifyApi.cs create mode 100644 src/Ombi.Api.Gotify/IGotifyApi.cs create mode 100644 src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj create mode 100644 src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs create mode 100644 src/Ombi.Notifications/Agents/GotifyNotification.cs create mode 100644 src/Ombi.Notifications/Agents/Interfaces/IGotifyNotification.cs create mode 100644 src/Ombi.Settings/Settings/Models/Notifications/GotifySettings.cs create mode 100644 src/Ombi/ClientApp/app/settings/notifications/gotify.component.html create mode 100644 src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts diff --git a/README.md b/README.md index 61cda24f3..0af908f65 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ We integrate with the following applications: Supported notifications: * SMTP Notifications (Email) * Discord +* Gotify * Slack * Pushbullet * Pushover diff --git a/src/Ombi.Api.Gotify/GotifyApi.cs b/src/Ombi.Api.Gotify/GotifyApi.cs new file mode 100644 index 000000000..8cd79a689 --- /dev/null +++ b/src/Ombi.Api.Gotify/GotifyApi.cs @@ -0,0 +1,36 @@ +using System.Net.Http; +using System.Threading.Tasks; + +namespace Ombi.Api.Gotify +{ + public class GotifyApi : IGotifyApi + { + public GotifyApi(IApi api) + { + _api = api; + } + + private readonly IApi _api; + + public async Task PushAsync(string baseUrl, string accessToken, string subject, string body, sbyte priority) + { + var request = new Request("/message", baseUrl, HttpMethod.Post); + request.AddQueryString("token", accessToken); + + request.AddHeader("Access-Token", accessToken); + request.ApplicationJsonContentType(); + + + var jsonBody = new + { + message = body, + title = subject, + priority = priority + }; + + request.AddJsonBody(jsonBody); + + await _api.Request(request); + } + } +} diff --git a/src/Ombi.Api.Gotify/IGotifyApi.cs b/src/Ombi.Api.Gotify/IGotifyApi.cs new file mode 100644 index 000000000..e6a6b4060 --- /dev/null +++ b/src/Ombi.Api.Gotify/IGotifyApi.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Api.Gotify +{ + public interface IGotifyApi + { + Task PushAsync(string endpoint, string accessToken, string subject, string body, sbyte priority); + } +} \ No newline at end of file diff --git a/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj new file mode 100644 index 000000000..ce5475fae --- /dev/null +++ b/src/Ombi.Api.Gotify/Ombi.Api.Gotify.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + 3.0.0.0 + 3.0.0.0 + + + + + + + + + diff --git a/src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs b/src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs new file mode 100644 index 000000000..93ce66724 --- /dev/null +++ b/src/Ombi.Core/Models/UI/GotifyNotificationViewModel.cs @@ -0,0 +1,23 @@ + +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 GotifyNotificationViewModel : GotifySettings + { + /// + /// Gets or sets the notification templates. + /// + /// + /// The notification templates. + /// + public List NotificationTemplates { get; set; } + + } +} diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 68a363706..69e6bd3ca 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -32,6 +32,7 @@ using Ombi.Api.CouchPotato; using Ombi.Api.DogNzb; using Ombi.Api.FanartTv; using Ombi.Api.Github; +using Ombi.Api.Gotify; using Ombi.Api.Lidarr; using Ombi.Api.Mattermost; using Ombi.Api.Notifications; @@ -120,6 +121,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -170,6 +172,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 3893dc879..0723800ab 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -32,6 +32,7 @@ namespace Ombi.Helpers public static EventId MattermostNotification => new EventId(4004); public static EventId PushoverNotification => new EventId(4005); public static EventId TelegramNotifcation => new EventId(4006); + public static EventId GotifyNotification => new EventId(4007); public static EventId TvSender => new EventId(5000); public static EventId SonarrSender => new EventId(5001); diff --git a/src/Ombi.Helpers/NotificationAgent.cs b/src/Ombi.Helpers/NotificationAgent.cs index 8990eeba9..18f28105a 100644 --- a/src/Ombi.Helpers/NotificationAgent.cs +++ b/src/Ombi.Helpers/NotificationAgent.cs @@ -10,5 +10,6 @@ Slack = 5, Mattermost = 6, Mobile = 7, + Gotify = 8, } } \ No newline at end of file diff --git a/src/Ombi.Mapping/Profiles/SettingsProfile.cs b/src/Ombi.Mapping/Profiles/SettingsProfile.cs index 139290f2b..f460ce78b 100644 --- a/src/Ombi.Mapping/Profiles/SettingsProfile.cs +++ b/src/Ombi.Mapping/Profiles/SettingsProfile.cs @@ -19,6 +19,7 @@ namespace Ombi.Mapping.Profiles CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); } } } \ No newline at end of file diff --git a/src/Ombi.Notifications/Agents/GotifyNotification.cs b/src/Ombi.Notifications/Agents/GotifyNotification.cs new file mode 100644 index 000000000..e1c9fc1db --- /dev/null +++ b/src/Ombi.Notifications/Agents/GotifyNotification.cs @@ -0,0 +1,116 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Ombi.Api.Gotify; +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 GotifyNotification : BaseNotification, IGotifyNotification + { + public GotifyNotification(IGotifyApi 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 => "GotifyNotification"; + + private IGotifyApi Api { get; } + private ILogger Logger { get; } + + protected override bool ValidateConfiguration(GotifySettings settings) + { + return settings.Enabled && !string.IsNullOrEmpty(settings.BaseUrl) && !string.IsNullOrEmpty(settings.ApplicationToken); + } + + protected override async Task NewRequest(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.NewRequest); + } + + + protected override async Task NewIssue(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.Issue); + } + + protected override async Task IssueComment(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.IssueComment); + } + + protected override async Task IssueResolved(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.IssueResolved); + } + + protected override async Task AddedToRequestQueue(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.ItemAddedToFaultQueue); + } + + protected override async Task RequestDeclined(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.RequestDeclined); + } + + protected override async Task RequestApproved(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.RequestApproved); + } + + protected override async Task AvailableRequest(NotificationOptions model, GotifySettings settings) + { + await Run(model, settings, NotificationType.RequestAvailable); + } + + protected override async Task Send(NotificationMessage model, GotifySettings settings) + { + try + { + await Api.PushAsync(settings.BaseUrl, settings.ApplicationToken, model.Subject, model.Message, settings.Priority); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.GotifyNotification, e, "Failed to send Gotify notification"); + } + } + + protected override async Task Test(NotificationOptions model, GotifySettings 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, GotifySettings settings, NotificationType type) + { + var parsed = await LoadTemplate(NotificationAgent.Gotify, type, model); + if (parsed.Disabled) + { + Logger.LogInformation($"Template {type} is disabled for {NotificationAgent.Gotify}"); + return; + } + + var notification = new NotificationMessage + { + Message = parsed.Message, + }; + + await Send(notification, settings); + } + } +} diff --git a/src/Ombi.Notifications/Agents/Interfaces/IGotifyNotification.cs b/src/Ombi.Notifications/Agents/Interfaces/IGotifyNotification.cs new file mode 100644 index 000000000..a85421938 --- /dev/null +++ b/src/Ombi.Notifications/Agents/Interfaces/IGotifyNotification.cs @@ -0,0 +1,6 @@ +namespace Ombi.Notifications.Agents +{ + public interface IGotifyNotification : INotification + { + } +} \ No newline at end of file diff --git a/src/Ombi.Notifications/Ombi.Notifications.csproj b/src/Ombi.Notifications/Ombi.Notifications.csproj index 2b5c95154..3fa4b4830 100644 --- a/src/Ombi.Notifications/Ombi.Notifications.csproj +++ b/src/Ombi.Notifications/Ombi.Notifications.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Ombi.Settings/Settings/Models/Notifications/GotifySettings.cs b/src/Ombi.Settings/Settings/Models/Notifications/GotifySettings.cs new file mode 100644 index 000000000..f0325b0f2 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/Notifications/GotifySettings.cs @@ -0,0 +1,10 @@ +namespace Ombi.Settings.Settings.Models.Notifications +{ + public class GotifySettings : Settings + { + public bool Enabled { get; set; } + public string BaseUrl { get; set; } + public string ApplicationToken { get; set; } + public sbyte Priority { get; set; } = 4; + } +} \ No newline at end of file diff --git a/src/Ombi.sln b/src/Ombi.sln index 2b9be2c42..f4f683c11 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -96,7 +96,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Notifications", "O EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Lidarr", "Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj", "{4FA21A20-92F4-462C-B929-2C517A88CC56}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Helpers.Tests", "Ombi.Helpers.Tests\Ombi.Helpers.Tests.csproj", "{CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Helpers.Tests", "Ombi.Helpers.Tests\Ombi.Helpers.Tests.csproj", "{CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Gotify", "Ombi.Api.Gotify\Ombi.Api.Gotify.csproj", "{105EA346-766E-45B8-928B-DE6991DCB7EB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -256,6 +258,10 @@ Global {CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC8CEFCD-0CB6-45BB-845F-508BCAB5BDC3}.Release|Any CPU.Build.0 = Release|Any CPU + {105EA346-766E-45B8-928B-DE6991DCB7EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -293,6 +299,7 @@ Global {10D1FE9D-9124-42B7-B1E1-CEB99B832618} = {9293CA11-360A-4C20-A674-B9E794431BF5} {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} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869} diff --git a/src/Ombi/ClientApp/app/interfaces/INotificationSettings.ts b/src/Ombi/ClientApp/app/interfaces/INotificationSettings.ts index f368ee035..5472a6c7c 100644 --- a/src/Ombi/ClientApp/app/interfaces/INotificationSettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/INotificationSettings.ts @@ -93,6 +93,14 @@ export interface IPushoverNotificationSettings extends INotificationSettings { sound: string; } +export interface IGotifyNotificationSettings extends INotificationSettings { + accessToken: string; + notificationTemplates: INotificationTemplates[]; + baseUrl: string; + applicationToken: string; + priority: number; +} + export interface IMattermostNotifcationSettings extends INotificationSettings { webhookUrl: string; username: string; diff --git a/src/Ombi/ClientApp/app/services/applications/tester.service.ts b/src/Ombi/ClientApp/app/services/applications/tester.service.ts index e692b9196..af619d583 100644 --- a/src/Ombi/ClientApp/app/services/applications/tester.service.ts +++ b/src/Ombi/ClientApp/app/services/applications/tester.service.ts @@ -11,6 +11,7 @@ import { IDiscordNotifcationSettings, IEmailNotificationSettings, IEmbyServer, + IGotifyNotificationSettings, ILidarrSettings, IMattermostNotifcationSettings, IMobileNotificationTestSettings, @@ -40,7 +41,11 @@ export class TesterService extends ServiceHelpers { } public pushoverTest(settings: IPushoverNotificationSettings): Observable { - return this.http.post(`${this.url}pushover`, JSON.stringify(settings), {headers: this.headers}); + return this.http.post(`${this.url}pushover`, JSON.stringify(settings), { headers: this.headers }); + } + + public gotifyTest(settings: IGotifyNotificationSettings): Observable { + return this.http.post(`${this.url}gotify`, JSON.stringify(settings), { headers: this.headers }); } public mattermostTest(settings: IMattermostNotifcationSettings): Observable { diff --git a/src/Ombi/ClientApp/app/services/settings.service.ts b/src/Ombi/ClientApp/app/services/settings.service.ts index 64a6edd14..a80cfd772 100644 --- a/src/Ombi/ClientApp/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/app/services/settings.service.ts @@ -14,6 +14,7 @@ import { IDogNzbSettings, IEmailNotificationSettings, IEmbySettings, + IGotifyNotificationSettings, IIssueSettings, IJobSettings, IJobSettingsViewModel, @@ -182,6 +183,14 @@ export class SettingsService extends ServiceHelpers { .post(`${this.url}/notifications/pushover`, JSON.stringify(settings), {headers: this.headers}); } + public getGotifyNotificationSettings(): Observable { + return this.http.get(`${this.url}/notifications/gotify`, { headers: this.headers }); + } + public saveGotifyNotificationSettings(settings: IGotifyNotificationSettings): Observable { + return this.http + .post(`${this.url}/notifications/gotify`, JSON.stringify(settings), { headers: this.headers }); + } + public getSlackNotificationSettings(): Observable { return this.http.get(`${this.url}/notifications/slack`, {headers: this.headers}); } diff --git a/src/Ombi/ClientApp/app/settings/notifications/gotify.component.html b/src/Ombi/ClientApp/app/settings/notifications/gotify.component.html new file mode 100644 index 000000000..9148cb880 --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/notifications/gotify.component.html @@ -0,0 +1,67 @@ + + +
+
+ Gotify Notifications +
+
+ +
+
+ + +
+
+ +
+ + + + The Base URL is required +
+ +
+ + + + The Application Token is required +
+ +
+ +
+ +
+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+ + +
+ +
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts b/src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts new file mode 100644 index 000000000..f6c08d41b --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts @@ -0,0 +1,68 @@ +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; + +import { IGotifyNotificationSettings, INotificationTemplates, NotificationType } from "../../interfaces"; +import { TesterService } from "../../services"; +import { NotificationService } from "../../services"; +import { SettingsService } from "../../services"; + +@Component({ + templateUrl: "./gotify.component.html", +}) +export class GotifyComponent implements OnInit { + public NotificationType = NotificationType; + public templates: INotificationTemplates[]; + public form: FormGroup; + + constructor(private settingsService: SettingsService, + private notificationService: NotificationService, + private fb: FormBuilder, + private testerService: TesterService) { } + + public ngOnInit() { + this.settingsService.getGotifyNotificationSettings().subscribe(x => { + this.templates = x.notificationTemplates; + + this.form = this.fb.group({ + enabled: [x.enabled], + baseUrl: [x.baseUrl, [Validators.required]], + applicationToken: [x.applicationToken, [Validators.required]], + priority: [x.priority], + }); + }); + } + + public onSubmit(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Please check your entered values"); + return; + } + + const settings = form.value; + settings.notificationTemplates = this.templates; + + this.settingsService.saveGotifyNotificationSettings(settings).subscribe(x => { + if (x) { + this.notificationService.success("Successfully saved the Gotify settings"); + } else { + this.notificationService.success("There was an error when saving the Gotify settings"); + } + }); + + } + + public test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Please check your entered values"); + return; + } + + this.testerService.gotifyTest(form.value).subscribe(x => { + if (x) { + this.notificationService.success("Successfully sent a Gotify message"); + } else { + this.notificationService.error("There was an error when sending the Gotify message. Please check your settings"); + } + }); + } +} diff --git a/src/Ombi/ClientApp/app/settings/settings.module.ts b/src/Ombi/ClientApp/app/settings/settings.module.ts index fb1a10abe..6fb69dc27 100644 --- a/src/Ombi/ClientApp/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/app/settings/settings.module.ts @@ -27,6 +27,7 @@ import { LidarrComponent } from "./lidarr/lidarr.component"; import { MassEmailComponent } from "./massemail/massemail.component"; import { DiscordComponent } from "./notifications/discord.component"; import { EmailNotificationComponent } from "./notifications/emailnotification.component"; +import { GotifyComponent } from "./notifications/gotify.component"; import { MattermostComponent } from "./notifications/mattermost.component"; import { MobileComponent } from "./notifications/mobile.component"; import { NewsletterComponent } from "./notifications/newsletter.component"; @@ -63,6 +64,7 @@ const routes: Routes = [ { path: "Slack", component: SlackComponent, canActivate: [AuthGuard] }, { path: "Pushover", component: PushoverComponent, canActivate: [AuthGuard] }, { path: "Pushbullet", component: PushbulletComponent, canActivate: [AuthGuard] }, + { path: "Gotify", component: GotifyComponent, canActivate: [AuthGuard] }, { path: "Mattermost", component: MattermostComponent, canActivate: [AuthGuard] }, { path: "UserManagement", component: UserManagementComponent, canActivate: [AuthGuard] }, { path: "Update", component: UpdateComponent, canActivate: [AuthGuard] }, @@ -117,6 +119,7 @@ const routes: Routes = [ PushoverComponent, MattermostComponent, PushbulletComponent, + GotifyComponent, UserManagementComponent, UpdateComponent, AboutComponent, diff --git a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html index 91405d1c5..81f901ecc 100644 --- a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html +++ b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html @@ -74,6 +74,7 @@
  • Pushover
  • Mattermost
  • Telegram
  • +
  • Gotify
  • diff --git a/src/Ombi/Controllers/External/TesterController.cs b/src/Ombi/Controllers/External/TesterController.cs index 5e3156bde..2894542f6 100644 --- a/src/Ombi/Controllers/External/TesterController.cs +++ b/src/Ombi/Controllers/External/TesterController.cs @@ -40,7 +40,7 @@ namespace Ombi.Controllers.External IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm, IPlexApi plex, IEmbyApi emby, IRadarrApi radarr, ISonarrApi sonarr, ILogger log, IEmailProvider provider, ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, IMobileNotification mobileNotification, - ILidarrApi lidarrApi) + ILidarrApi lidarrApi, IGotifyNotification gotifyNotification) { Service = service; DiscordNotification = notification; @@ -61,6 +61,7 @@ namespace Ombi.Controllers.External Newsletter = newsletter; MobileNotification = mobileNotification; LidarrApi = lidarrApi; + GotifyNotification = gotifyNotification; } private INotificationService Service { get; } @@ -69,6 +70,7 @@ namespace Ombi.Controllers.External private IPushbulletNotification PushbulletNotification { get; } private ISlackNotification SlackNotification { get; } private IPushoverNotification PushoverNotification { get; } + private IGotifyNotification GotifyNotification { get; } private IMattermostNotification MattermostNotification { get; } private IPlexApi PlexApi { get; } private IRadarrApi RadarrApi { get; } @@ -155,6 +157,30 @@ namespace Ombi.Controllers.External } + /// + /// Sends a test message to Gotify using the provided settings + /// + /// The settings. + /// + [HttpPost("gotify")] + public bool Gotify([FromBody] GotifySettings settings) + { + try + { + settings.Enabled = true; + GotifyNotification.NotifyAsync( + new NotificationOptions { NotificationType = NotificationType.Test, RequestId = -1 }, settings); + + return true; + } + catch (Exception e) + { + Log.LogError(LoggingEvents.Api, e, "Could not test Gotify"); + return false; + } + + } + /// /// Sends a test message to mattermost using the provided settings /// diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index b5ec57e29..823461e35 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -947,6 +947,40 @@ namespace Ombi.Controllers return model; } + /// + /// Saves the gotify notification settings. + /// + /// The model. + /// + [HttpPost("notifications/gotify")] + public async Task GotifyNotificationSettings([FromBody] GotifyNotificationViewModel model) + { + // Save the email settings + var settings = Mapper.Map(model); + var result = await Save(settings); + + // Save the templates + await TemplateRepository.UpdateRange(model.NotificationTemplates); + + return result; + } + + /// + /// Gets the gotify Notification Settings. + /// + /// + [HttpGet("notifications/gotify")] + public async Task GotifyNotificationSettings() + { + var settings = await Get(); + var model = Mapper.Map(settings); + + // Lookup to see if we have any templates saved + model.NotificationTemplates = BuildTemplates(NotificationAgent.Gotify); + + return model; + } + /// /// Saves the Newsletter notification settings. /// From 41d96238975b663a92664507ef62d09e153ece74 Mon Sep 17 00:00:00 2001 From: Guillaume Taquet Gasperini Date: Wed, 20 Mar 2019 19:57:21 +0100 Subject: [PATCH 08/20] Fix cake build by setting Incubator version --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index e8e4bb8c0..c25447906 100644 --- a/build.cake +++ b/build.cake @@ -3,7 +3,7 @@ #addin "Cake.Gulp" #addin "SharpZipLib" #addin nuget:?package=Cake.Compression&version=0.1.4 -#addin "Cake.Incubator" +#addin "Cake.Incubator&version=3.1.0" #addin "Cake.Yarn" ////////////////////////////////////////////////////////////////////// From 4920ac3da0ce947f522e8ec01b283e608f6f88ec Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 21 Mar 2019 15:33:10 +0000 Subject: [PATCH 09/20] Take out the lastlogindate update for now #2750 --- src/Ombi/Controllers/TokenController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index 44ec5686f..6604c6dbb 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -124,7 +124,7 @@ namespace Ombi.Controllers } user.LastLoggedIn = DateTime.UtcNow; - await _userManager.UpdateAsync(user); + //await _userManager.UpdateAsync(user); var claims = new List { From 826517cbfff0db35ee51ab858cab5a8f198d9d10 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 21 Mar 2019 15:34:22 +0000 Subject: [PATCH 10/20] !wip --- src/Ombi/Controllers/TokenController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi/Controllers/TokenController.cs b/src/Ombi/Controllers/TokenController.cs index 9499dd493..9f9747f0e 100644 --- a/src/Ombi/Controllers/TokenController.cs +++ b/src/Ombi/Controllers/TokenController.cs @@ -150,7 +150,7 @@ namespace Ombi.Controllers } user.LastLoggedIn = DateTime.UtcNow; - await GlobalMutex.Lock(async () => await _userManager.UpdateAsync(user)).ConfigureAwait(false); + //await GlobalMutex.Lock(async () => await _userManager.UpdateAsync(user)).ConfigureAwait(false); return new JsonResult(new { From cf9bb889edaf4afa34c4504808432b07ca061672 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 22 Mar 2019 22:31:11 +0000 Subject: [PATCH 11/20] Fixed the issue where it was not picking up roles until the JWT was refreshed --- .../Rule/Request/CanRequestRuleTests.cs | 1 + .../Rule/Rules/Request/AutoApproveRule.cs | 21 +++++++----- .../Rule/Rules/Request/CanRequestRule.cs | 34 +++++++++++-------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs index c9db5875a..69b6a76df 100644 --- a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Moq; using NUnit.Framework; using Ombi.Core.Rule.Rules; +using Ombi.Core.Rule.Rules.Request; using Ombi.Helpers; using Ombi.Store.Entities.Requests; diff --git a/src/Ombi.Core/Rule/Rules/Request/AutoApproveRule.cs b/src/Ombi.Core/Rule/Rules/Request/AutoApproveRule.cs index a55868db8..685f02b54 100644 --- a/src/Ombi.Core/Rule/Rules/Request/AutoApproveRule.cs +++ b/src/Ombi.Core/Rule/Rules/Request/AutoApproveRule.cs @@ -1,5 +1,7 @@ using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Authentication; using Ombi.Core.Models.Requests; using Ombi.Core.Rule.Interfaces; using Ombi.Helpers; @@ -10,28 +12,31 @@ namespace Ombi.Core.Rule.Rules.Request { public class AutoApproveRule : BaseRequestRule, IRules { - public AutoApproveRule(IPrincipal principal) + public AutoApproveRule(IPrincipal principal, OmbiUserManager um) { User = principal; + _manager = um; } private IPrincipal User { get; } + private readonly OmbiUserManager _manager; - public Task Execute(BaseRequest obj) + public async Task Execute(BaseRequest obj) { - if (User.IsInRole(OmbiRoles.Admin)) + var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name); + if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin)) { obj.Approved = true; - return Task.FromResult(Success()); + return Success(); } - if (obj.RequestType == RequestType.Movie && User.IsInRole(OmbiRoles.AutoApproveMovie)) + if (obj.RequestType == RequestType.Movie && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie)) obj.Approved = true; - if (obj.RequestType == RequestType.TvShow && User.IsInRole(OmbiRoles.AutoApproveTv)) + if (obj.RequestType == RequestType.TvShow && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv)) obj.Approved = true; - if (obj.RequestType == RequestType.Album && User.IsInRole(OmbiRoles.AutoApproveMusic)) + if (obj.RequestType == RequestType.Album && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic)) obj.Approved = true; - return Task.FromResult(Success()); // We don't really care, we just don't set the obj to approve + return Success(); // We don't really care, we just don't set the obj to approve } } } \ No newline at end of file diff --git a/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs b/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs index 1cdf03955..a2c70fcc5 100644 --- a/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs +++ b/src/Ombi.Core/Rule/Rules/Request/CanRequestRule.cs @@ -1,46 +1,52 @@ -using Ombi.Store.Entities; +using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Authentication; using Ombi.Core.Rule.Interfaces; using Ombi.Helpers; +using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; -namespace Ombi.Core.Rule.Rules +namespace Ombi.Core.Rule.Rules.Request { public class CanRequestRule : BaseRequestRule, IRules { - public CanRequestRule(IPrincipal principal) + public CanRequestRule(IPrincipal principal, OmbiUserManager manager) { User = principal; + _manager = manager; } private IPrincipal User { get; } + private readonly OmbiUserManager _manager; - public Task Execute(BaseRequest obj) + public async Task Execute(BaseRequest obj) { - if (User.IsInRole(OmbiRoles.Admin)) - return Task.FromResult(Success()); + var user = await _manager.Users.FirstOrDefaultAsync(x => x.UserName == User.Identity.Name); + if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin)) + return Success(); if (obj.RequestType == RequestType.Movie) { - if (User.IsInRole(OmbiRoles.RequestMovie) || User.IsInRole(OmbiRoles.AutoApproveMovie)) - return Task.FromResult(Success()); - return Task.FromResult(Fail("You do not have permissions to Request a Movie")); + if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie)) + return Success(); + return Fail("You do not have permissions to Request a Movie"); } if (obj.RequestType == RequestType.TvShow) { - if (User.IsInRole(OmbiRoles.RequestTv) || User.IsInRole(OmbiRoles.AutoApproveTv)) - return Task.FromResult(Success()); + if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestTv) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv)) + return Success(); } if (obj.RequestType == RequestType.Album) { - if (User.IsInRole(OmbiRoles.RequestMusic) || User.IsInRole(OmbiRoles.AutoApproveMusic)) - return Task.FromResult(Success()); + if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMusic) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic)) + return Success(); } - return Task.FromResult(Fail("You do not have permissions to Request a TV Show")); + return Fail("You do not have permissions to Request a TV Show"); } } } \ No newline at end of file From 89e275df744ded175fec2492e1282c8045ccc563 Mon Sep 17 00:00:00 2001 From: Jamie Date: Sat, 23 Mar 2019 00:08:04 +0000 Subject: [PATCH 12/20] Update JobSetup.cs --- src/Ombi.Schedule/JobSetup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index 38686396f..811f5ca42 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -81,7 +81,7 @@ namespace Ombi.Schedule RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s)); RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s)); RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s)); - RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s)); + // RecurringJob.AddOrUpdate(() => _resender.Start(), JobSettingsHelper.ResendFailedRequests(s)); RecurringJob.AddOrUpdate(() => _mediaDatabaseRefresh.Start(), JobSettingsHelper.MediaDatabaseRefresh(s)); } From 775e18e2d3e6efc163ce65630aeb5e830df1d08d Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Mon, 25 Mar 2019 08:25:18 +0000 Subject: [PATCH 13/20] Fixed #2803 in regards to the Request Button showing up. Still need to investiagte the availability side of things --- src/Ombi/ClientApp/app/search/music/albumsearch.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi/ClientApp/app/search/music/albumsearch.component.html b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html index 8f2fe73ce..2b31df040 100644 --- a/src/Ombi/ClientApp/app/search/music/albumsearch.component.html +++ b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html @@ -80,7 +80,7 @@ {{ 'Common.Available' | translate }}
    -
    +
    From 42662924d94097fdd76fa83c09d1b2f30f69e7f2 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Mon, 25 Mar 2019 08:31:31 +0000 Subject: [PATCH 14/20] Removed the auditing, was not used anyway #2750 --- src/Ombi.Core/Engine/TvRequestEngine.cs | 16 +++------ src/Ombi/package-lock.json | 47 ++++++++----------------- 2 files changed, 18 insertions(+), 45 deletions(-) diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index 58144d3ce..1cb0ad65a 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -31,14 +31,13 @@ namespace Ombi.Core.Engine { public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user, INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, - ITvSender sender, IAuditRepository audit, IRepository rl, ISettingsService settings, ICacheService cache, + ITvSender sender, IRepository rl, ISettingsService settings, ICacheService cache, IRepository sub) : base(user, requestService, rule, manager, cache, settings, sub) { TvApi = tvApi; MovieDbApi = movApi; NotificationHelper = helper; TvSender = sender; - Audit = audit; _requestLog = rl; } @@ -46,7 +45,6 @@ namespace Ombi.Core.Engine private ITvMazeApi TvApi { get; } private IMovieDbApi MovieDbApi { get; } private ITvSender TvSender { get; } - private IAuditRepository Audit { get; } private readonly IRepository _requestLog; public async Task RequestTvShow(TvRequestViewModel tv) @@ -351,7 +349,6 @@ namespace Ombi.Core.Engine public async Task UpdateTvRequest(TvRequests request) { - await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username); var allRequests = TvRepository.Get(); var results = await allRequests.FirstOrDefaultAsync(x => x.Id == request.Id); @@ -394,7 +391,6 @@ namespace Ombi.Core.Engine if (request.Approved) { NotificationHelper.Notify(request, NotificationType.RequestApproved); - await Audit.Record(AuditType.Approved, AuditArea.TvRequest, $"Approved Request {request.Title}", Username); // Autosend await TvSender.Send(request); } @@ -426,9 +422,7 @@ namespace Ombi.Core.Engine public async Task UpdateChildRequest(ChildRequests request) { - await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username); - - await TvRepository.UpdateChild(request); + await TvRepository.UpdateChild(request); return request; } @@ -446,16 +440,14 @@ namespace Ombi.Core.Engine // Delete the parent TvRepository.Db.TvRequests.Remove(parent); } - await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username); - + await TvRepository.Db.SaveChangesAsync(); } public async Task RemoveTvRequest(int requestId) { var request = await TvRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId); - await Audit.Record(AuditType.Deleted, AuditArea.TvRequest, $"Deleting Request {request.Title}", Username); - await TvRepository.Delete(request); + await TvRepository.Delete(request); } public async Task UserHasRequest(string userId) diff --git a/src/Ombi/package-lock.json b/src/Ombi/package-lock.json index 4ad391ab8..fff834922 100644 --- a/src/Ombi/package-lock.json +++ b/src/Ombi/package-lock.json @@ -1766,9 +1766,9 @@ } }, "bootstrap": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.0.tgz", - "integrity": "sha512-F1yTDO9OHKH0xjl03DsOe8Nu1OWBIeAugGMhy3UTIYDdbbIPesQIhCEbj+HEr6wqlwweGAlP8F3OBC6kEuhFuw==" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" }, "bootswatch": { "version": "3.4.0", @@ -4190,8 +4190,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -4209,13 +4208,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4228,18 +4225,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -4342,8 +4336,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -4353,7 +4346,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4366,20 +4358,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4396,7 +4385,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4469,8 +4457,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -4480,7 +4467,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4556,8 +4542,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -4587,7 +4572,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4605,7 +4589,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4644,13 +4627,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, From e6e24c6a97447ca2a8762eaee4c24539395183ff Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Mon, 25 Mar 2019 08:41:15 +0000 Subject: [PATCH 15/20] More for #2750 --- src/Ombi.Store/Repository/BaseRepository.cs | 2 +- .../Repository/EmbyContentRepository.cs | 7 +++--- .../NotificationTemplatesRepository.cs | 11 +++++++--- .../Repository/PlexContentRepository.cs | 10 ++++----- .../Requests/MovieRequestRepository.cs | 10 +++++++-- .../Requests/MusicRequestRepository.cs | 9 ++++++-- .../Requests/TvRequestRepository.cs | 22 ++++++++++++------- .../Repository/SettingsJsonRepository.cs | 9 ++++++-- src/Ombi.Store/Repository/TokenRepository.cs | 7 +++++- 9 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/Ombi.Store/Repository/BaseRepository.cs b/src/Ombi.Store/Repository/BaseRepository.cs index ca2937291..1ca78ee50 100644 --- a/src/Ombi.Store/Repository/BaseRepository.cs +++ b/src/Ombi.Store/Repository/BaseRepository.cs @@ -81,7 +81,7 @@ namespace Ombi.Store.Repository await _ctx.Database.ExecuteSqlCommandAsync(sql); } - private async Task InternalSaveChanges() + protected async Task InternalSaveChanges() { return await GlobalMutex.Lock(async () => await _ctx.SaveChangesAsync()); } diff --git a/src/Ombi.Store/Repository/EmbyContentRepository.cs b/src/Ombi.Store/Repository/EmbyContentRepository.cs index 4d32e8da2..2ada709ab 100644 --- a/src/Ombi.Store/Repository/EmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/EmbyContentRepository.cs @@ -72,7 +72,7 @@ namespace Ombi.Store.Repository public async Task Update(EmbyContent existingContent) { Db.EmbyContent.Update(existingContent); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public IQueryable GetAllEpisodes() @@ -83,7 +83,7 @@ namespace Ombi.Store.Repository public async Task Add(EmbyEpisode content) { await Db.EmbyEpisode.AddAsync(content); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); return content; } public async Task GetEpisodeByEmbyId(string key) @@ -94,12 +94,13 @@ namespace Ombi.Store.Repository public async Task AddRange(IEnumerable content) { Db.EmbyEpisode.AddRange(content); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public void UpdateWithoutSave(EmbyContent existingContent) { Db.EmbyContent.Update(existingContent); } + } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs b/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs index 175d0e6a9..eb4816d50 100644 --- a/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs +++ b/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs @@ -45,7 +45,7 @@ namespace Ombi.Store.Repository Db.Attach(template); Db.Entry(template).State = EntityState.Modified; } - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task UpdateRange(IEnumerable templates) @@ -56,16 +56,21 @@ namespace Ombi.Store.Repository Db.Attach(t); Db.Entry(t).State = EntityState.Modified; } - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task Insert(NotificationTemplates entity) { var settings = await Db.NotificationTemplates.AddAsync(entity).ConfigureAwait(false); - await Db.SaveChangesAsync().ConfigureAwait(false); + await InternalSaveChanges().ConfigureAwait(false); return settings.Entity; } + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + } + private bool _disposed; // Protected implementation of Dispose pattern. protected virtual void Dispose(bool disposing) diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index 2c9c28d09..37275a47c 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -96,7 +96,7 @@ namespace Ombi.Store.Repository public async Task Update(PlexServerContent existingContent) { Db.PlexServerContent.Update(existingContent); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public void UpdateWithoutSave(PlexServerContent existingContent) { @@ -106,7 +106,7 @@ namespace Ombi.Store.Repository public async Task UpdateRange(IEnumerable existingContent) { Db.PlexServerContent.UpdateRange(existingContent); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public IQueryable GetAllEpisodes() @@ -127,14 +127,14 @@ namespace Ombi.Store.Repository public async Task Add(PlexEpisode content) { await Db.PlexEpisode.AddAsync(content); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); return content; } public async Task DeleteEpisode(PlexEpisode content) { Db.PlexEpisode.Remove(content); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task GetEpisodeByKey(int key) @@ -144,7 +144,7 @@ namespace Ombi.Store.Repository public async Task AddRange(IEnumerable content) { Db.PlexEpisode.AddRange(content); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs b/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs index d4a550528..d96363d29 100644 --- a/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities.Requests; @@ -70,12 +71,17 @@ namespace Ombi.Store.Repository.Requests Db.MovieRequests.Attach(request); Db.Update(request); } - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task Save() { - await Db.SaveChangesAsync(); + await InternalSaveChanges(); + } + + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs b/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs index 59edf265a..5179513d2 100644 --- a/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities.Requests; @@ -61,12 +62,16 @@ namespace Ombi.Store.Repository.Requests Db.AlbumRequests.Attach(request); Db.Update(request); } - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task Save() { - await Db.SaveChangesAsync(); + await InternalSaveChanges(); + } + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs index daac7d4df..d3486358a 100644 --- a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities.Requests; @@ -101,20 +102,20 @@ namespace Ombi.Store.Repository.Requests public async Task Save() { - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task Add(TvRequests request) { await Db.TvRequests.AddAsync(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); return request; } public async Task AddChild(ChildRequests request) { await Db.ChildRequests.AddAsync(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); return request; } @@ -122,33 +123,38 @@ namespace Ombi.Store.Repository.Requests public async Task Delete(TvRequests request) { Db.TvRequests.Remove(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task DeleteChild(ChildRequests request) { Db.ChildRequests.Remove(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task DeleteChildRange(IEnumerable request) { Db.ChildRequests.RemoveRange(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task Update(TvRequests request) { Db.Update(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task UpdateChild(ChildRequests request) { Db.Update(request); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); + } + + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/SettingsJsonRepository.cs b/src/Ombi.Store/Repository/SettingsJsonRepository.cs index 66cf57b18..6140fd7a1 100644 --- a/src/Ombi.Store/Repository/SettingsJsonRepository.cs +++ b/src/Ombi.Store/Repository/SettingsJsonRepository.cs @@ -62,14 +62,14 @@ namespace Ombi.Store.Repository { //_cache.Remove(GetName(entity.SettingsName)); Db.Settings.Remove(entity); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public async Task UpdateAsync(GlobalSettings entity) { //_cache.Remove(GetName(entity.SettingsName)); Db.Update(entity); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public void Delete(GlobalSettings entity) @@ -91,6 +91,11 @@ namespace Ombi.Store.Repository return $"{entity}Json"; } + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + } + private bool _disposed; protected virtual void Dispose(bool disposing) { diff --git a/src/Ombi.Store/Repository/TokenRepository.cs b/src/Ombi.Store/Repository/TokenRepository.cs index d766c5690..3f82e3948 100644 --- a/src/Ombi.Store/Repository/TokenRepository.cs +++ b/src/Ombi.Store/Repository/TokenRepository.cs @@ -4,6 +4,7 @@ using Ombi.Store.Entities; using System; using System.Linq; using System.Threading.Tasks; +using Ombi.Helpers; namespace Ombi.Store.Repository { @@ -19,12 +20,16 @@ namespace Ombi.Store.Repository public async Task CreateToken(Tokens token) { await Db.Tokens.AddAsync(token); - await Db.SaveChangesAsync(); + await InternalSaveChanges(); } public IQueryable GetToken(string tokenId) { return Db.Tokens.Where(x => x.Token == tokenId); } + private async Task InternalSaveChanges() + { + return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + } } } From 5d9e6bd1130d7cebe2f8679bd161c046e4340896 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Mon, 25 Mar 2019 09:24:32 +0000 Subject: [PATCH 16/20] Fixed build !wip --- src/Ombi.Core/Engine/TvRequestEngine.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index 1cb0ad65a..796e2fe6a 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -82,8 +82,6 @@ namespace Ombi.Core.Engine } } - await Audit.Record(AuditType.Added, AuditArea.TvRequest, $"Added Request {tvBuilder.ChildRequest.Title}", Username); - var existingRequest = await TvRepository.Get().FirstOrDefaultAsync(x => x.TvDbId == tv.TvDbId); if (existingRequest != null) { From 117bd1cd8b14a5d93c495139918631a30ca1d3f4 Mon Sep 17 00:00:00 2001 From: Jamie Rees Date: Tue, 26 Mar 2019 12:12:58 +0000 Subject: [PATCH 17/20] #2750 stuff --- .../Authentication/OmbiUserManager.cs | 2 +- src/Ombi.DependencyInjection/IocExtensions.cs | 36 +++++++++---------- src/Ombi.Store/Context/OmbiContext.cs | 1 + src/Ombi/Startup.cs | 3 -- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/Ombi.Core/Authentication/OmbiUserManager.cs b/src/Ombi.Core/Authentication/OmbiUserManager.cs index 2c78f39bf..6155672b3 100644 --- a/src/Ombi.Core/Authentication/OmbiUserManager.cs +++ b/src/Ombi.Core/Authentication/OmbiUserManager.cs @@ -158,7 +158,7 @@ namespace Ombi.Core.Authentication if (!email.Equals(result.User?.Email)) { user.Email = result.User?.Email; - await UpdateAsync(user); + await GlobalMutex.Lock(async () => await UpdateAsync(user)); } return true; diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 69e6bd3ca..466b74bb0 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -134,28 +134,28 @@ namespace Ombi.DependencyInjection } public static void RegisterStore(this IServiceCollection services) { - services.AddEntityFrameworkSqlite().AddDbContext(); - services.AddEntityFrameworkSqlite().AddDbContext(); - services.AddEntityFrameworkSqlite().AddDbContext(); + services.AddDbContext(); + services.AddDbContext(); + services.AddDbContext(); services.AddScoped(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6 services.AddScoped(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6 services.AddScoped(); // https://docs.microsoft.com/en-us/aspnet/core/data/entity-framework-6 - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(typeof(ISettingsService<>), typeof(SettingsService<>)); - services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); - services.AddTransient(typeof(IExternalRepository<>), typeof(ExternalRepository<>)); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(typeof(ISettingsService<>), typeof(SettingsService<>)); + services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); + services.AddScoped(typeof(IExternalRepository<>), typeof(ExternalRepository<>)); } public static void RegisterServices(this IServiceCollection services) { @@ -163,7 +163,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); services.AddTransient(); services.AddTransient(); diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index 2f19bc681..98f4cd9c3 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -17,6 +17,7 @@ namespace Ombi.Store.Context { if (_created) return; + _created = true; Database.SetCommandTimeout(60); Database.Migrate(); diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index bbf56c517..fa70df147 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -56,9 +56,6 @@ namespace Ombi // This method gets called by the runtime. Use this method to add services to the container. public IServiceProvider ConfigureServices(IServiceCollection services) { - // Add framework services. - services.AddDbContext(); - services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders() From a499782ec0dc445abdfd14c7f999c876df901b04 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 26 Mar 2019 22:12:47 +0000 Subject: [PATCH 18/20] Delete the schedules db on startup, we don't want it trying to recover the jobs --- src/Ombi/Program.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Ombi/Program.cs b/src/Ombi/Program.cs index f1809a2dc..2365f6748 100644 --- a/src/Ombi/Program.cs +++ b/src/Ombi/Program.cs @@ -49,6 +49,7 @@ namespace Ombi demoInstance.Demo = demo; instance.StoragePath = storagePath ?? string.Empty; // Check if we need to migrate the settings + DeleteSchedules(); CheckAndMigrate(); var ctx = new SettingsContext(); var config = ctx.ApplicationConfigurations.ToList(); @@ -97,6 +98,20 @@ namespace Ombi CreateWebHostBuilder(args).Build().Run(); } + private static void DeleteSchedules() + { + try + { + if (File.Exists("Schedules.db")) + { + File.Delete("Schedules.db"); + } + } + catch (Exception) + { + } + } + /// /// This is to remove the Settings from the Ombi.db to the "new" /// OmbiSettings.db From 439dc395d05ba08ff0e06ba49bf0b4cfc69e160f Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 27 Mar 2019 10:19:36 +0000 Subject: [PATCH 19/20] Reverted the global app lock for the db #2750 --- .../Rule/Request/AutoApproveRuleTests.cs | 3 +- .../Rule/Request/CanRequestRuleTests.cs | 2 +- .../Rule/Search/EmbyAvailabilityRuleTests.cs | 2 +- .../Authentication/OmbiUserManager.cs | 2 +- src/Ombi.Helpers/GlobalMutex.cs | 39 ------------------- src/Ombi.Store/Repository/BaseRepository.cs | 2 +- .../NotificationTemplatesRepository.cs | 2 +- .../Requests/MovieRequestRepository.cs | 5 --- .../Requests/MusicRequestRepository.cs | 4 -- .../Requests/TvRequestRepository.cs | 2 +- .../Repository/SettingsJsonRepository.cs | 2 +- src/Ombi.Store/Repository/TokenRepository.cs | 2 +- 12 files changed, 10 insertions(+), 57 deletions(-) delete mode 100644 src/Ombi.Helpers/GlobalMutex.cs diff --git a/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs index 7ff8283da..34c21e008 100644 --- a/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/AutoApproveRuleTests.cs @@ -4,6 +4,7 @@ using Moq; using Ombi.Core.Rule.Rules.Request; using Ombi.Store.Entities.Requests; using NUnit.Framework; +using Ombi.Core.Authentication; using Ombi.Helpers; namespace Ombi.Core.Tests.Rule.Request @@ -16,7 +17,7 @@ namespace Ombi.Core.Tests.Rule.Request { PrincipalMock = new Mock(); - Rule = new AutoApproveRule(PrincipalMock.Object); + Rule = new AutoApproveRule(PrincipalMock.Object, null); } diff --git a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs index 69b6a76df..f2781c8d2 100644 --- a/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/CanRequestRuleTests.cs @@ -16,7 +16,7 @@ namespace Ombi.Core.Tests.Rule.Request { PrincipalMock = new Mock(); - Rule = new CanRequestRule(PrincipalMock.Object); + Rule = new CanRequestRule(PrincipalMock.Object, null); } diff --git a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs index 99ff5b6bd..0171e37a1 100644 --- a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs @@ -16,7 +16,7 @@ namespace Ombi.Core.Tests.Rule.Search public void Setup() { ContextMock = new Mock(); - Rule = new EmbyAvailabilityRule(ContextMock.Object); + Rule = new EmbyAvailabilityRule(ContextMock.Object, null); } private EmbyAvailabilityRule Rule { get; set; } diff --git a/src/Ombi.Core/Authentication/OmbiUserManager.cs b/src/Ombi.Core/Authentication/OmbiUserManager.cs index 6155672b3..2c78f39bf 100644 --- a/src/Ombi.Core/Authentication/OmbiUserManager.cs +++ b/src/Ombi.Core/Authentication/OmbiUserManager.cs @@ -158,7 +158,7 @@ namespace Ombi.Core.Authentication if (!email.Equals(result.User?.Email)) { user.Email = result.User?.Email; - await GlobalMutex.Lock(async () => await UpdateAsync(user)); + await UpdateAsync(user); } return true; diff --git a/src/Ombi.Helpers/GlobalMutex.cs b/src/Ombi.Helpers/GlobalMutex.cs deleted file mode 100644 index 0164e888c..000000000 --- a/src/Ombi.Helpers/GlobalMutex.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Nito.AsyncEx; - -namespace Ombi.Helpers -{ - public static class GlobalMutex - { - public static async Task Lock(Func> func) - { - const string mutexId = "Global\\OMBI"; - using (var mutex = new Mutex(false, mutexId, out _)) - { - var hasHandle = false; - try - { - try - { - hasHandle = mutex.WaitOne(5000, false); - if (hasHandle == false) - throw new TimeoutException("Timeout waiting for exclusive access"); - } - catch (AbandonedMutexException) - { - hasHandle = true; - } - - return await func(); - } - finally - { - if (hasHandle) - mutex.ReleaseMutex(); - } - } - } - } -} diff --git a/src/Ombi.Store/Repository/BaseRepository.cs b/src/Ombi.Store/Repository/BaseRepository.cs index 1ca78ee50..0741a79b6 100644 --- a/src/Ombi.Store/Repository/BaseRepository.cs +++ b/src/Ombi.Store/Repository/BaseRepository.cs @@ -83,7 +83,7 @@ namespace Ombi.Store.Repository protected async Task InternalSaveChanges() { - return await GlobalMutex.Lock(async () => await _ctx.SaveChangesAsync()); + return await _ctx.SaveChangesAsync(); } diff --git a/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs b/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs index eb4816d50..8f3968dc0 100644 --- a/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs +++ b/src/Ombi.Store/Repository/NotificationTemplatesRepository.cs @@ -68,7 +68,7 @@ namespace Ombi.Store.Repository private async Task InternalSaveChanges() { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + return await Db.SaveChangesAsync(); } private bool _disposed; diff --git a/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs b/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs index d96363d29..2cea81200 100644 --- a/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/MovieRequestRepository.cs @@ -78,10 +78,5 @@ namespace Ombi.Store.Repository.Requests { await InternalSaveChanges(); } - - private async Task InternalSaveChanges() - { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); - } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs b/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs index 5179513d2..971d53b39 100644 --- a/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/MusicRequestRepository.cs @@ -69,9 +69,5 @@ namespace Ombi.Store.Repository.Requests { await InternalSaveChanges(); } - private async Task InternalSaveChanges() - { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); - } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs index d3486358a..91e885b37 100644 --- a/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/TvRequestRepository.cs @@ -154,7 +154,7 @@ namespace Ombi.Store.Repository.Requests private async Task InternalSaveChanges() { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + return await Db.SaveChangesAsync(); } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/SettingsJsonRepository.cs b/src/Ombi.Store/Repository/SettingsJsonRepository.cs index 6140fd7a1..909a68480 100644 --- a/src/Ombi.Store/Repository/SettingsJsonRepository.cs +++ b/src/Ombi.Store/Repository/SettingsJsonRepository.cs @@ -93,7 +93,7 @@ namespace Ombi.Store.Repository private async Task InternalSaveChanges() { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + return await Db.SaveChangesAsync(); } private bool _disposed; diff --git a/src/Ombi.Store/Repository/TokenRepository.cs b/src/Ombi.Store/Repository/TokenRepository.cs index 3f82e3948..d0a501bd5 100644 --- a/src/Ombi.Store/Repository/TokenRepository.cs +++ b/src/Ombi.Store/Repository/TokenRepository.cs @@ -29,7 +29,7 @@ namespace Ombi.Store.Repository } private async Task InternalSaveChanges() { - return await GlobalMutex.Lock(async () => await Db.SaveChangesAsync()); + return await Db.SaveChangesAsync(); } } } From 18ae38731d5b28097c44d052bec6ff2c3d45def5 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 27 Mar 2019 10:51:14 +0000 Subject: [PATCH 20/20] Fixed build --- .../{ => src}/app/settings/notifications/gotify.component.html | 0 .../{ => src}/app/settings/notifications/gotify.component.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/Ombi/ClientApp/{ => src}/app/settings/notifications/gotify.component.html (100%) rename src/Ombi/ClientApp/{ => src}/app/settings/notifications/gotify.component.ts (100%) diff --git a/src/Ombi/ClientApp/app/settings/notifications/gotify.component.html b/src/Ombi/ClientApp/src/app/settings/notifications/gotify.component.html similarity index 100% rename from src/Ombi/ClientApp/app/settings/notifications/gotify.component.html rename to src/Ombi/ClientApp/src/app/settings/notifications/gotify.component.html diff --git a/src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts b/src/Ombi/ClientApp/src/app/settings/notifications/gotify.component.ts similarity index 100% rename from src/Ombi/ClientApp/app/settings/notifications/gotify.component.ts rename to src/Ombi/ClientApp/src/app/settings/notifications/gotify.component.ts