diff --git a/CHANGELOG.md b/CHANGELOG.md index e94945927..82ac6457d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,20 @@ # Changelog -## (unreleased) +## v3.0.3268 (2018-04-28) + +### **Fixes** + +- Potential fix for #2119. [Jamie Rees] + +- Use the Application URL if we have it to fix #2201. [Jamie] + + +## v3.0.3239 (2018-04-26) ### **New Features** +- Update appveyor.yml. [Jamie] + - Added paging to the TV Requests page. [Jamie Rees] - Added Paging to the Movie Requests Page. [Jamie Rees] @@ -18,6 +29,8 @@ ### **Fixes** +- Clean up the error code when the OAuth user is not authorized. [Jamie] + - More improvements to the Plex OAuth, Added the ability to turn it off if needed. [Jamie] - Fixed bug #2188 #2134. [Jamie] diff --git a/src/Ombi.Api.Plex/Models/Metadata.cs b/src/Ombi.Api.Plex/Models/Metadata.cs index dcde62818..cda6ce68b 100644 --- a/src/Ombi.Api.Plex/Models/Metadata.cs +++ b/src/Ombi.Api.Plex/Models/Metadata.cs @@ -11,15 +11,15 @@ namespace Ombi.Api.Plex.Models public string summary { get; set; } public int index { get; set; } public float rating { get; set; } - public int viewCount { get; set; } - public int lastViewedAt { get; set; } + //public int viewCount { get; set; } + //public int lastViewedAt { get; set; } public int year { get; set; } public string thumb { get; set; } public string art { get; set; } public string banner { get; set; } public string theme { get; set; } - public string duration { get; set; } - public string originallyAvailableAt { get; set; } + //public string duration { get; set; } + //public string originallyAvailableAt { get; set; } public int leafCount { get; set; } public int viewedLeafCount { get; set; } public int childCount { get; set; } diff --git a/src/Ombi.Core/Authentication/PlexOAuthManager.cs b/src/Ombi.Core/Authentication/PlexOAuthManager.cs index f3a3e4d01..37ed7d2f7 100644 --- a/src/Ombi.Core/Authentication/PlexOAuthManager.cs +++ b/src/Ombi.Core/Authentication/PlexOAuthManager.cs @@ -57,21 +57,8 @@ namespace Ombi.Core.Authentication public async Task GetOAuthUrl(int pinId, string code, string websiteAddress = null) { - Uri url; - if (websiteAddress.IsNullOrEmpty()) - { - var settings = await _customizationSettingsService.GetSettingsAsync(); - if (settings.ApplicationUrl.IsNullOrEmpty()) - { - return null; - } - - url = _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl, false); - } - else - { - url = _api.GetOAuthUrl(pinId, code, websiteAddress, false); - } + var settings = await _customizationSettingsService.GetSettingsAsync(); + var url = _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl.IsNullOrEmpty() ? websiteAddress : settings.ApplicationUrl, false); return url; } diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs index 2f765fede..08ec9b594 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs @@ -17,7 +17,7 @@ namespace Ombi.Core.Engine.Interfaces Task ApproveMovie(MovieRequests request); Task ApproveMovieById(int requestId); Task DenyMovieById(int modelId); - Task> Filter(FilterViewModel vm); + Task> Filter(FilterViewModel vm); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 0e47a28f6..3d88b7230 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -131,11 +131,11 @@ namespace Ombi.Core.Engine List allRequests; if (shouldHide.Hide) { - allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).Skip(position).Take(count).ToListAsync(); + allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); } else { - allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).ToListAsync(); + allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); } allRequests.ForEach(x => { @@ -380,10 +380,13 @@ namespace Ombi.Core.Engine return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!" }; } - public async Task> Filter(FilterViewModel vm) + public async Task> Filter(FilterViewModel vm) { var shouldHide = await HideFromOtherUsers(); - var requests = shouldHide.Hide ? MovieRepository.GetWithUser(shouldHide.UserId) : MovieRepository.GetWithUser(); + var requests = shouldHide.Hide + ? MovieRepository.GetWithUser(shouldHide.UserId) + : MovieRepository.GetWithUser(); + switch (vm.AvailabilityFilter) { case FilterType.None: @@ -415,7 +418,14 @@ namespace Ombi.Core.Engine throw new ArgumentOutOfRangeException(); } - return requests; + var count = await requests.CountAsync(); + requests = requests.Skip(vm.Position).Take(vm.Count); + var retVal = new FilterResult + { + Total = count, + Collection = requests + }; + return retVal; } } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index c3f1139bf..2ce4da292 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -141,7 +141,7 @@ namespace Ombi.Core.Engine .Include(x => x.ChildRequests) .ThenInclude(x => x.SeasonRequests) .ThenInclude(x => x.Episodes) - .Skip(position).Take(count).ToListAsync(); + .Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); // Filter out children @@ -153,7 +153,7 @@ namespace Ombi.Core.Engine .Include(x => x.ChildRequests) .ThenInclude(x => x.SeasonRequests) .ThenInclude(x => x.Episodes) - .Skip(position).Take(count).ToListAsync(); + .Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); } return allRequests; diff --git a/src/Ombi.Core/Models/Requests/FilterResult.cs b/src/Ombi.Core/Models/Requests/FilterResult.cs new file mode 100644 index 000000000..467b9731a --- /dev/null +++ b/src/Ombi.Core/Models/Requests/FilterResult.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Ombi.Core.Models.Requests +{ + public class FilterResult + { + public int Total { get; set; } + public IEnumerable Collection { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Models/Requests/FilterViewModel.cs b/src/Ombi.Core/Models/Requests/FilterViewModel.cs index 27ccc39d6..25a9d5ef1 100644 --- a/src/Ombi.Core/Models/Requests/FilterViewModel.cs +++ b/src/Ombi.Core/Models/Requests/FilterViewModel.cs @@ -4,6 +4,8 @@ { public FilterType AvailabilityFilter { get; set; } public FilterType StatusFilter { get; set; } + public int Position { get; set; } + public int Count { get; set; } } public enum FilterType diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index c5a365bf6..68f4b7218 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -177,6 +177,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } } } diff --git a/src/Ombi.Notifications/Agents/MobileNotification.cs b/src/Ombi.Notifications/Agents/MobileNotification.cs index 05c02dfef..575801bd2 100644 --- a/src/Ombi.Notifications/Agents/MobileNotification.cs +++ b/src/Ombi.Notifications/Agents/MobileNotification.cs @@ -39,7 +39,7 @@ namespace Ombi.Notifications.Agents protected override bool ValidateConfiguration(MobileNotificationSettings settings) { - return false; + return true; } protected override async Task NewRequest(NotificationOptions model, MobileNotificationSettings settings) @@ -211,7 +211,7 @@ namespace Ombi.Notifications.Agents protected async Task Send(List playerIds, NotificationMessage model, MobileNotificationSettings settings) { - if (!playerIds.Any()) + if (playerIds == null || !playerIds.Any()) { return; } diff --git a/src/Ombi.Schedule.Tests/NewsletterTests.cs b/src/Ombi.Schedule.Tests/NewsletterTests.cs new file mode 100644 index 000000000..fcbd35107 --- /dev/null +++ b/src/Ombi.Schedule.Tests/NewsletterTests.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Moq; +using NUnit.Framework; +using Ombi.Core.Settings; +using Ombi.Schedule.Jobs.Ombi; +using Ombi.Settings.Settings.Models; +using Ombi.Settings.Settings.Models.Notifications; +using Ombi.Store.Entities; + +namespace Ombi.Schedule.Tests +{ + [TestFixture] + public class NewsletterTests + { + [TestCaseSource(nameof(EpisodeListData))] + public string BuildEpisodeListTest(List episodes) + { + var emailSettings = new Mock>(); + var customziation = new Mock>(); + var newsletterSettings = new Mock>(); + var newsletter = new NewsletterJob(null, null, null, null, null, null, customziation.Object, emailSettings.Object, null, null, newsletterSettings.Object, null); + + var ep = new List(); + foreach (var i in episodes) + { + ep.Add(i); + } + var result = newsletter.BuildEpisodeList(ep); + return result; + } + + public static IEnumerable EpisodeListData + { + get + { + yield return new TestCaseData(new List{1,2,3,4,5,6}).Returns("1-6").SetName("Simple 1-6"); + yield return new TestCaseData(new List{1,2,3,4,5,6,8,9}).Returns("1-6, 8-9").SetName("Simple 1-6, 8-9"); + yield return new TestCaseData(new List{1,99,101,555,468,469}).Returns("1, 99, 101, 555, 468-469").SetName("More Complex"); + yield return new TestCaseData(new List{1}).Returns("1").SetName("Single Episode"); + } + } + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj index eae150067..1805b80f2 100644 --- a/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj +++ b/src/Ombi.Schedule.Tests/Ombi.Schedule.Tests.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index 73d7c3536..44997f272 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -19,7 +19,7 @@ namespace Ombi.Schedule IOmbiAutomaticUpdater updater, IEmbyContentSync embySync, IPlexUserImporter userImporter, IEmbyUserImporter embyUserImporter, ISonarrSync cache, ICouchPotatoSync cpCache, ISettingsService jobsettings, ISickRageSync srSync, IRefreshMetadata refresh, - INewsletterJob newsletter) + INewsletterJob newsletter, IPlexRecentlyAddedSync recentlyAddedPlex) { _plexContentSync = plexContentSync; _radarrSync = radarrSync; @@ -33,9 +33,11 @@ namespace Ombi.Schedule _srSync = srSync; _refreshMetadata = refresh; _newsletter = newsletter; + _plexRecentlyAddedSync = recentlyAddedPlex; } private readonly IPlexContentSync _plexContentSync; + private readonly IPlexRecentlyAddedSync _plexRecentlyAddedSync; private readonly IRadarrSync _radarrSync; private readonly IOmbiAutomaticUpdater _updater; private readonly IPlexUserImporter _plexUserImporter; @@ -56,7 +58,7 @@ namespace Ombi.Schedule RecurringJob.AddOrUpdate(() => _sonarrSync.Start(), JobSettingsHelper.Sonarr(s)); RecurringJob.AddOrUpdate(() => _radarrSync.CacheContent(), JobSettingsHelper.Radarr(s)); RecurringJob.AddOrUpdate(() => _plexContentSync.CacheContent(false), JobSettingsHelper.PlexContent(s)); - RecurringJob.AddOrUpdate(() => _plexContentSync.CacheContent(true), JobSettingsHelper.PlexRecentlyAdded(s)); + RecurringJob.AddOrUpdate(() => _plexRecentlyAddedSync.Start(), JobSettingsHelper.PlexRecentlyAdded(s)); RecurringJob.AddOrUpdate(() => _cpCache.Start(), JobSettingsHelper.CouchPotato(s)); RecurringJob.AddOrUpdate(() => _srSync.Start(), JobSettingsHelper.SickRageSync(s)); RecurringJob.AddOrUpdate(() => _refreshMetadata.Start(), JobSettingsHelper.RefreshMetadata(s)); diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 4d0026f48..acea1535e 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -9,6 +9,7 @@ using Ombi.Api.Emby.Models.Movie; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; +using Ombi.Schedule.Jobs.Ombi; using Ombi.Store.Entities; using Ombi.Store.Repository; using Serilog; @@ -19,13 +20,14 @@ namespace Ombi.Schedule.Jobs.Emby public class EmbyContentSync : IEmbyContentSync { public EmbyContentSync(ISettingsService settings, IEmbyApi api, ILogger logger, - IEmbyContentRepository repo, IEmbyEpisodeSync epSync) + IEmbyContentRepository repo, IEmbyEpisodeSync epSync, IRefreshMetadata metadata) { _logger = logger; _settings = settings; _api = api; _repo = repo; _episodeSync = epSync; + _metadata = metadata; _settings.ClearCache(); } @@ -34,6 +36,7 @@ namespace Ombi.Schedule.Jobs.Emby private readonly IEmbyApi _api; private readonly IEmbyContentRepository _repo; private readonly IEmbyEpisodeSync _episodeSync; + private readonly IRefreshMetadata _metadata; public async Task Start() @@ -56,6 +59,7 @@ namespace Ombi.Schedule.Jobs.Emby // Episodes BackgroundJob.Enqueue(() => _episodeSync.Start()); + BackgroundJob.Enqueue(() => _metadata.Start()); } diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 7a46acea1..6336abf6e 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -98,14 +98,14 @@ namespace Ombi.Schedule.Jobs.Ombi addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode); // Filter out the ones that we haven't sent yet - var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); + var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && x.HasTheMovieDb && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); + var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && x.HasTheMovieDb && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); _log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count()); _log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count()); var plexEpisodesToSend = - FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds); - var embyEpisodesToSend = FilterEmbyEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), + FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds); + var embyEpisodesToSend = FilterEmbyEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedEmbyEpisodesLogIds); _log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count()); @@ -114,7 +114,7 @@ namespace Ombi.Schedule.Jobs.Ombi if (test) { var plexm = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie).OrderByDescending(x => x.AddedAt).Take(10); - var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); + var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie ).OrderByDescending(x => x.AddedAt).Take(10); var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet(); var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); body = await BuildHtml(plexm, embym, plext, embyt, settings); @@ -564,21 +564,8 @@ namespace Ombi.Schedule.Jobs.Ombi foreach (var epInformation in results.OrderBy(x => x.SeasonNumber)) { var orderedEpisodes = epInformation.Episodes.OrderBy(x => x.EpisodeNumber).ToList(); - var epSb = new StringBuilder(); - for (var i = 0; i < orderedEpisodes.Count; i++) - { - var ep = orderedEpisodes[i]; - if (i < orderedEpisodes.Count - 1) - { - epSb.Append($"{ep.EpisodeNumber},"); - } - else - { - epSb.Append($"{ep.EpisodeNumber}"); - } - - } - finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {epSb}"); + var episodeString = BuildEpisodeList(orderedEpisodes.Select(x => x.EpisodeNumber)); + finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {episodeString}"); finalsb.Append("
"); } @@ -615,6 +602,49 @@ namespace Ombi.Schedule.Jobs.Ombi } } + public string BuildEpisodeList(IEnumerable orderedEpisodes) + { + var epSb = new StringBuilder(); + var previousEpisodes = new List(); + var previousEpisode = -1; + foreach (var ep in orderedEpisodes) + { + if (ep - 1 == previousEpisode) + { + // This is the next one + previousEpisodes.Add(ep); + } + else + { + if (previousEpisodes.Count > 1) + { + // End it + epSb.Append($"{previousEpisodes.First()}-{previousEpisodes.Last()}, "); + } + else if (previousEpisodes.Count == 1) + { + epSb.Append($"{previousEpisodes.FirstOrDefault()}, "); + } + // New one + previousEpisodes.Clear(); + previousEpisodes.Add(ep); + } + previousEpisode = ep; + } + + if (previousEpisodes.Count > 1) + { + // Got some left over + epSb.Append($"{previousEpisodes.First()}-{previousEpisodes.Last()}"); + } + else if(previousEpisodes.Count == 1) + { + epSb.Append(previousEpisodes.FirstOrDefault()); + } + + return epSb.ToString(); + } + private async Task ProcessEmbyTv(HashSet embyContent, StringBuilder sb) { var series = new List(); @@ -688,21 +718,8 @@ namespace Ombi.Schedule.Jobs.Ombi foreach (var epInformation in results.OrderBy(x => x.SeasonNumber)) { var orderedEpisodes = epInformation.Episodes.OrderBy(x => x.EpisodeNumber).ToList(); - var epSb = new StringBuilder(); - for (var i = 0; i < orderedEpisodes.Count; i++) - { - var ep = orderedEpisodes[i]; - if (i < orderedEpisodes.Count - 1) - { - epSb.Append($"{ep.EpisodeNumber},"); - } - else - { - epSb.Append($"{ep.EpisodeNumber}"); - } - - } - finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {epSb}"); + var episodeString = BuildEpisodeList(orderedEpisodes.Select(x => x.EpisodeNumber)); + finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {episodeString}"); finalsb.Append("
"); } diff --git a/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexRecentlyAddedSync.cs b/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexRecentlyAddedSync.cs new file mode 100644 index 000000000..34f5562a6 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexRecentlyAddedSync.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Schedule.Jobs.Plex +{ + public interface IPlexRecentlyAddedSync : IBaseJob + { + void Start(); + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 0292b6b54..334b51e4b 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -37,6 +37,7 @@ using Ombi.Api.Plex.Models; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; +using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Plex.Interfaces; using Ombi.Store.Entities; using Ombi.Store.Repository; @@ -46,13 +47,14 @@ namespace Ombi.Schedule.Jobs.Plex public class PlexContentSync : IPlexContentSync { public PlexContentSync(ISettingsService plex, IPlexApi plexApi, ILogger logger, IPlexContentRepository repo, - IPlexEpisodeSync epsiodeSync) + IPlexEpisodeSync epsiodeSync, IRefreshMetadata metadataRefresh) { Plex = plex; PlexApi = plexApi; Logger = logger; Repo = repo; EpisodeSync = epsiodeSync; + Metadata = metadataRefresh; plex.ClearCache(); } @@ -61,6 +63,7 @@ namespace Ombi.Schedule.Jobs.Plex private ILogger Logger { get; } private IPlexContentRepository Repo { get; } private IPlexEpisodeSync EpisodeSync { get; } + private IRefreshMetadata Metadata { get; } public async Task CacheContent(bool recentlyAddedSearch = false) { @@ -87,6 +90,7 @@ namespace Ombi.Schedule.Jobs.Plex Logger.LogInformation("Starting EP Cacher"); BackgroundJob.Enqueue(() => EpisodeSync.Start()); + BackgroundJob.Enqueue(() => Metadata.Start()); } private async Task StartTheCache(PlexSettings plexSettings, bool recentlyAddedSearch) @@ -115,187 +119,30 @@ namespace Ombi.Schedule.Jobs.Plex var contentToAdd = new HashSet(); foreach (var content in allContent) { + if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.CurrentCultureIgnoreCase)) + { + Logger.LogInformation("Found some episodes, this must be a recently added sync"); + foreach (var epInfo in content.Metadata) + { + var grandParentKey = epInfo.grandparentRatingKey; + // Lookup the rating key + var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, grandParentKey); + var show = showMetadata.MediaContainer.Metadata.FirstOrDefault(); + if(show == null) + { + continue; + } + + await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch); + } + } if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)) { // Process Shows Logger.LogInformation("Processing TV Shows"); foreach (var show in content.Metadata ?? new Metadata[] { }) { - var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri, - show.ratingKey); - var seasonsContent = new List(); - foreach (var season in seasonList.MediaContainer.Metadata) - { - seasonsContent.Add(new PlexSeasonsContent - { - ParentKey = season.parentRatingKey, - SeasonKey = season.ratingKey, - SeasonNumber = season.index, - PlexContentId = show.ratingKey - }); - } - - // Do we already have this item? - // Let's try and match - var existingContent = await Repo.GetFirstContentByCustom(x => x.Title == show.title - && x.ReleaseYear == show.year.ToString() - && x.Type == PlexMediaTypeEntity.Show); - - // Just double check the rating key, since this is our unique constraint - var existingKey = await Repo.GetByKey(show.ratingKey); - - if (existingKey != null) - { - // Damn son. - // Let's check if they match up - var doesMatch = show.title.Equals(existingKey.Title, - StringComparison.CurrentCulture); - if (!doesMatch) - { - // Something fucked up on Plex at somepoint... Damn, rebuild of lib maybe? - // Lets delete the matching key - await Repo.Delete(existingKey); - existingKey = null; - } - } - - if (existingContent != null) - { - // Just check the key - if (existingKey != null) - { - // The rating key is all good! - } - else - { - // This means the rating key has changed somehow. - // Should probably delete this and get the new one - var oldKey = existingContent.Key; - Repo.DeleteWithoutSave(existingContent); - - // Because we have changed the rating key, we need to change all children too - var episodeToChange = Repo.GetAllEpisodes().Where(x => x.GrandparentKey == oldKey); - if (episodeToChange.Any()) - { - foreach (var e in episodeToChange) - { - Repo.DeleteWithoutSave(e); - } - } - await Repo.SaveChangesAsync(); - existingContent = null; - } - } - // The ratingKey keeps changing... - //var existingContent = await Repo.GetByKey(show.ratingKey); - if (existingContent != null) - { - try - { - Logger.LogInformation("We already have show {0} checking for new seasons", - existingContent.Title); - // Ok so we have it, let's check if there are any new seasons - var itemAdded = false; - foreach (var season in seasonsContent) - { - var seasonExists = - existingContent.Seasons.FirstOrDefault(x => x.SeasonKey == season.SeasonKey); - - if (seasonExists != null) - { - // We already have this season - continue; - } - - existingContent.Seasons.Add(season); - itemAdded = true; - } - - if (itemAdded) await Repo.Update(existingContent); - } - catch (Exception e) - { - Logger.LogError(LoggingEvents.PlexContentCacher, e, - "Exception when adding new seasons to title {0}", existingContent.Title); - } - } - else - { - try - { - Logger.LogInformation("New show {0}, so add it", show.title); - - // Get the show metadata... This sucks since the `metadata` var contains all information about the show - // But it does not contain the `guid` property that we need to pull out thetvdb id... - var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, - show.ratingKey); - var providerIds = - PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault() - .guid); - - var item = new PlexServerContent - { - AddedAt = DateTime.Now, - Key = show.ratingKey, - ReleaseYear = show.year.ToString(), - Type = PlexMediaTypeEntity.Show, - Title = show.title, - Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey), - Seasons = new List() - }; - if (providerIds.Type == ProviderType.ImdbId) - { - item.ImdbId = providerIds.ImdbId; - } - if (providerIds.Type == ProviderType.TheMovieDbId) - { - item.TheMovieDbId = providerIds.TheMovieDb; - } - if (providerIds.Type == ProviderType.TvDbId) - { - item.TvDbId = providerIds.TheTvDb; - } - - // Let's just double check to make sure we do not have it now we have some id's - var existingImdb = false; - var existingMovieDbId = false; - var existingTvDbId = false; - if (item.ImdbId.HasValue()) - { - existingImdb = await Repo.GetAll().AnyAsync(x => - x.ImdbId == item.ImdbId && x.Type == PlexMediaTypeEntity.Show); - } - if (item.TheMovieDbId.HasValue()) - { - existingMovieDbId = await Repo.GetAll().AnyAsync(x => - x.TheMovieDbId == item.TheMovieDbId && x.Type == PlexMediaTypeEntity.Show); - } - if (item.TvDbId.HasValue()) - { - existingTvDbId = await Repo.GetAll().AnyAsync(x => - x.TvDbId == item.TvDbId && x.Type == PlexMediaTypeEntity.Show); - } - if (existingImdb || existingTvDbId || existingMovieDbId) - { - // We already have it! - continue; - } - - item.Seasons.ToList().AddRange(seasonsContent); - - contentToAdd.Add(item); - } - catch (Exception e) - { - Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding tv show {0}", - show.title); - } - } - if (contentToAdd.Count > 500) - { - await Repo.AddRange(contentToAdd); - contentToAdd.Clear(); - } + await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch); } } if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)) @@ -382,6 +229,193 @@ namespace Ombi.Schedule.Jobs.Plex } } + private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet contentToAdd, bool recentlyAdded) + { + var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri, + show.ratingKey); + var seasonsContent = new List(); + foreach (var season in seasonList.MediaContainer.Metadata) + { + seasonsContent.Add(new PlexSeasonsContent + { + ParentKey = season.parentRatingKey, + SeasonKey = season.ratingKey, + SeasonNumber = season.index, + PlexContentId = show.ratingKey + }); + } + + // Do we already have this item? + // Let's try and match + var existingContent = await Repo.GetFirstContentByCustom(x => x.Title == show.title + && x.ReleaseYear == show.year.ToString() + && x.Type == PlexMediaTypeEntity.Show); + + // Just double check the rating key, since this is our unique constraint + var existingKey = await Repo.GetByKey(show.ratingKey); + + if (existingKey != null) + { + // Damn son. + // Let's check if they match up + var doesMatch = show.title.Equals(existingKey.Title, + StringComparison.CurrentCulture); + if (!doesMatch) + { + // Something fucked up on Plex at somepoint... Damn, rebuild of lib maybe? + // Lets delete the matching key + await Repo.Delete(existingKey); + existingKey = null; + } + } + + if (existingContent != null) + { + // Just check the key + if (existingKey != null) + { + // The rating key is all good! + } + else + { + // This means the rating key has changed somehow. + // Should probably delete this and get the new one + var oldKey = existingContent.Key; + Repo.DeleteWithoutSave(existingContent); + + // Because we have changed the rating key, we need to change all children too + var episodeToChange = Repo.GetAllEpisodes().Where(x => x.GrandparentKey == oldKey); + if (episodeToChange.Any()) + { + foreach (var e in episodeToChange) + { + Repo.DeleteWithoutSave(e); + } + } + + await Repo.SaveChangesAsync(); + existingContent = null; + } + } + + // The ratingKey keeps changing... + //var existingContent = await Repo.GetByKey(show.ratingKey); + if (existingContent != null) + { + try + { + Logger.LogInformation("We already have show {0} checking for new seasons", + existingContent.Title); + // Ok so we have it, let's check if there are any new seasons + var itemAdded = false; + foreach (var season in seasonsContent) + { + var seasonExists = + existingContent.Seasons.FirstOrDefault(x => x.SeasonKey == season.SeasonKey); + + if (seasonExists != null) + { + // We already have this season + continue; + } + + existingContent.Seasons.Add(season); + itemAdded = true; + } + + if (itemAdded) await Repo.Update(existingContent); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.PlexContentCacher, e, + "Exception when adding new seasons to title {0}", existingContent.Title); + } + } + else + { + try + { + Logger.LogInformation("New show {0}, so add it", show.title); + + // Get the show metadata... This sucks since the `metadata` var contains all information about the show + // But it does not contain the `guid` property that we need to pull out thetvdb id... + var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri, + show.ratingKey); + var providerIds = + PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault() + .guid); + + var item = new PlexServerContent + { + AddedAt = DateTime.Now, + Key = show.ratingKey, + ReleaseYear = show.year.ToString(), + Type = PlexMediaTypeEntity.Show, + Title = show.title, + Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey), + Seasons = new List() + }; + if (providerIds.Type == ProviderType.ImdbId) + { + item.ImdbId = providerIds.ImdbId; + } + + if (providerIds.Type == ProviderType.TheMovieDbId) + { + item.TheMovieDbId = providerIds.TheMovieDb; + } + + if (providerIds.Type == ProviderType.TvDbId) + { + item.TvDbId = providerIds.TheTvDb; + } + + // Let's just double check to make sure we do not have it now we have some id's + var existingImdb = false; + var existingMovieDbId = false; + var existingTvDbId = false; + if (item.ImdbId.HasValue()) + { + existingImdb = await Repo.GetAll().AnyAsync(x => + x.ImdbId == item.ImdbId && x.Type == PlexMediaTypeEntity.Show); + } + + if (item.TheMovieDbId.HasValue()) + { + existingMovieDbId = await Repo.GetAll().AnyAsync(x => + x.TheMovieDbId == item.TheMovieDbId && x.Type == PlexMediaTypeEntity.Show); + } + + if (item.TvDbId.HasValue()) + { + existingTvDbId = await Repo.GetAll().AnyAsync(x => + x.TvDbId == item.TvDbId && x.Type == PlexMediaTypeEntity.Show); + } + + if (existingImdb || existingTvDbId || existingMovieDbId) + { + // We already have it! + return; + } + + item.Seasons.ToList().AddRange(seasonsContent); + + contentToAdd.Add(item); + } + catch (Exception e) + { + Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding tv show {0}", + show.title); + } + } + + if (contentToAdd.Count > 500 || recentlyAdded) + { + await Repo.AddRange(contentToAdd); + contentToAdd.Clear(); + } + } + /// /// Gets all the library sections. /// If the user has specified only certain libraries then we will only look for those diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs index 7d0fde4c7..8e8cce411 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs @@ -50,12 +50,13 @@ namespace Ombi.Schedule.Jobs.Plex await Cache(server); } - BackgroundJob.Enqueue(() => _availabilityChecker.Start()); } catch (Exception e) { _log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed"); } + + BackgroundJob.Enqueue(() => _availabilityChecker.Start()); } private async Task Cache(PlexServers settings) diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs b/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs index bf8ac1a75..2e2e9229e 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs @@ -31,6 +31,7 @@ namespace Ombi.Schedule.Jobs public enum PlexMediaType { Movie = 0, - Show = 1 + Show = 1, + Episode = 2, } } \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexRecentlyAddedSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexRecentlyAddedSync.cs new file mode 100644 index 000000000..51596f891 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Plex/PlexRecentlyAddedSync.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Hangfire; + +namespace Ombi.Schedule.Jobs.Plex +{ + public class PlexRecentlyAddedSync : IPlexRecentlyAddedSync + { + public PlexRecentlyAddedSync(IPlexContentSync sync) + { + _sync = sync; + } + + private readonly IPlexContentSync _sync; + + public void Start() + { + BackgroundJob.Enqueue(() => _sync.CacheContent(true)); + } + + private bool _disposed; + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + _sync?.Dispose(); + } + _disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs index c4fcb8ceb..2e56f17db 100644 --- a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs +++ b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs @@ -21,7 +21,7 @@ namespace Ombi.Settings.Settings.Models } public static string PlexContent(JobSettings s) { - return Get(s.PlexContentSync, Cron.HourInterval(6)); + return Get(s.PlexContentSync, Cron.Daily(2)); } public static string PlexRecentlyAdded(JobSettings s) { @@ -50,7 +50,7 @@ namespace Ombi.Settings.Settings.Models } public static string RefreshMetadata(JobSettings s) { - return Get(s.RefreshMetadata, Cron.Daily(3)); + return Get(s.RefreshMetadata, Cron.DayInterval(2)); } private static string Get(string settings, string defaultCron) diff --git a/src/Ombi.Store/Entities/EmbyContent.cs b/src/Ombi.Store/Entities/EmbyContent.cs index 4506ef071..348573f28 100644 --- a/src/Ombi.Store/Entities/EmbyContent.cs +++ b/src/Ombi.Store/Entities/EmbyContent.cs @@ -51,6 +51,15 @@ namespace Ombi.Store.Entities public string Url { get; set; } public ICollection Episodes { get; set; } + + [NotMapped] + public bool HasImdb => !string.IsNullOrEmpty(ImdbId); + + [NotMapped] + public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); + + [NotMapped] + public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } public enum EmbyMediaType diff --git a/src/Ombi.Tests/IdentityControllerTests.cs b/src/Ombi.Tests/IdentityControllerTests.cs index 978ec769c..72e76842d 100644 --- a/src/Ombi.Tests/IdentityControllerTests.cs +++ b/src/Ombi.Tests/IdentityControllerTests.cs @@ -1,132 +1,134 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AutoMapper; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Moq; -using NUnit.Framework; -using Ombi.Api.Emby; -using Ombi.Api.Plex; -using Ombi.Config; -using Ombi.Controllers; -using Ombi.Core.Authentication; -using Ombi.Core.Settings; -using Ombi.Core.Settings.Models.External; -using Ombi.Models; -using Ombi.Notifications; -using Ombi.Schedule.Jobs.Ombi; -using Ombi.Settings.Settings.Models; -using Ombi.Settings.Settings.Models.Notifications; -using Ombi.Store.Context; -using Ombi.Store.Entities; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading; +//using System.Threading.Tasks; +//using AutoMapper; +//using Microsoft.AspNetCore.Http; +//using Microsoft.AspNetCore.Http.Features.Authentication; +//using Microsoft.AspNetCore.Identity; +//using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +//using Microsoft.EntityFrameworkCore; +//using Microsoft.EntityFrameworkCore.Infrastructure; +//using Microsoft.Extensions.DependencyInjection; +//using Microsoft.Extensions.Options; +//using Moq; +//using NUnit.Framework; +//using Ombi.Api.Emby; +//using Ombi.Api.Plex; +//using Ombi.Config; +//using Ombi.Controllers; +//using Ombi.Core.Authentication; +//using Ombi.Core.Settings; +//using Ombi.Core.Settings.Models.External; +//using Ombi.Models; +//using Ombi.Notifications; +//using Ombi.Schedule.Jobs.Ombi; +//using Ombi.Settings.Settings.Models; +//using Ombi.Settings.Settings.Models.Notifications; +//using Ombi.Store.Context; +//using Ombi.Store.Entities; -namespace Ombi.Tests -{ - [TestFixture] - [Ignore("Need to sort out the DB, looks like it's using the real one...")] - public class IdentityControllerTests - { - [SetUp] - public void Setup() - { - _plexApi = new Mock(); - _embyApi = new Mock(); - _mapper = new Mock(); - _emailProvider = new Mock(); - _emailSettings = new Mock>(); - _customizationSettings = new Mock>(); - _welcomeEmail = new Mock(); - _embySettings = new Mock>(); - _plexSettings = new Mock>(); +//namespace Ombi.Tests +//{ +// [TestFixture] +// [Ignore("Need to sort out the DB, looks like it's using the real one...")] +// public class IdentityControllerTests +// { +// [SetUp] +// public void Setup() +// { +// _plexApi = new Mock(); +// _embyApi = new Mock(); +// _mapper = new Mock(); +// _emailProvider = new Mock(); +// _emailSettings = new Mock>(); +// _customizationSettings = new Mock>(); +// _welcomeEmail = new Mock(); +// _embySettings = new Mock>(); +// _plexSettings = new Mock>(); - var services = new ServiceCollection(); - services.AddEntityFrameworkInMemoryDatabase() - .AddDbContext(); - services.AddIdentity() - .AddEntityFrameworkStores().AddUserManager(); +// var services = new ServiceCollection(); +// services.AddEntityFrameworkInMemoryDatabase() +// .AddDbContext(); +// services.AddIdentity() +// .AddEntityFrameworkStores().AddUserManager(); - services.AddTransient(x => _plexApi.Object); - services.AddTransient(x => _embyApi.Object); - services.AddTransient(x => _customizationSettings.Object); - services.AddTransient(x => _welcomeEmail.Object); - services.AddTransient(x => _emailSettings.Object); - services.AddTransient(x => _emailProvider.Object); - services.AddTransient(x => _mapper.Object); - services.AddTransient(x => _embySettings.Object); - services.AddTransient(x => _plexSettings.Object); +// services.AddTransient(x => _plexApi.Object); +// services.AddTransient(x => _embyApi.Object); +// services.AddTransient(x => _customizationSettings.Object); +// services.AddTransient(x => _welcomeEmail.Object); +// services.AddTransient(x => _emailSettings.Object); +// services.AddTransient(x => _emailProvider.Object); +// services.AddTransient(x => _mapper.Object); +// services.AddTransient(x => _embySettings.Object); +// services.AddTransient(x => _plexSettings.Object); - services.Configure(options => - { - options.Password.RequireDigit = false; - options.Password.RequiredLength = 1; - options.Password.RequireLowercase = false; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - options.User.AllowedUserNameCharacters = string.Empty; - }); +// services.Configure(options => +// { +// options.Password.RequireDigit = false; +// options.Password.RequiredLength = 1; +// options.Password.RequireLowercase = false; +// options.Password.RequireNonAlphanumeric = false; +// options.Password.RequireUppercase = false; +// options.User.AllowedUserNameCharacters = string.Empty; +// }); - // Taken from https://github.com/aspnet/MusicStore/blob/dev/test/MusicStore.Test/ManageControllerTest.cs (and modified) - var context = new DefaultHttpContext(); - context.Features.Set(new HttpAuthenticationFeature()); - services.AddSingleton(h => new HttpContextAccessor { HttpContext = context }); - _serviceProvider = services.BuildServiceProvider(); - _userManager = _serviceProvider.GetRequiredService(); - - Controller = new IdentityController(_userManager, _mapper.Object, _serviceProvider.GetService>(), _emailProvider.Object, - _emailSettings.Object, _customizationSettings.Object,_welcomeEmail.Object, null, null, null, null, null, null, null, null); - } +// // Taken from https://github.com/aspnet/MusicStore/blob/dev/test/MusicStore.Test/ManageControllerTest.cs (and modified) +// var context = new DefaultHttpContext(); +// context.Features.Set(new HttpAuthenticationFeature()); +// services.AddSingleton(h => new HttpContextAccessor { HttpContext = context }); +// _serviceProvider = services.BuildServiceProvider(); +// _userManager = _serviceProvider.GetRequiredService(); - private OmbiUserManager _userManager; - private Mock _emailProvider; - private Mock> _emailSettings; - private Mock> _customizationSettings; - private Mock> _embySettings; - private Mock> _plexSettings; - private Mock _welcomeEmail; - private Mock _mapper; - private Mock _plexApi; - private Mock _embyApi; - private ServiceProvider _serviceProvider; +// Controller = new IdentityController(_userManager, _mapper.Object, +// _serviceProvider.GetService>(), _emailProvider.Object, +// _emailSettings.Object, _customizationSettings.Object, _welcomeEmail.Object, null, null, null, null, +// null, null, null, null, null); +// } - private IdentityController Controller { get; set; } +// private OmbiUserManager _userManager; +// private Mock _emailProvider; +// private Mock> _emailSettings; +// private Mock> _customizationSettings; +// private Mock> _embySettings; +// private Mock> _plexSettings; +// private Mock _welcomeEmail; +// private Mock _mapper; +// private Mock _plexApi; +// private Mock _embyApi; +// private ServiceProvider _serviceProvider; - [Test] - public async Task CreateWizardUser_Should_CreateUser_WhenThereAreNoOtherUsers() - { - var model = new CreateUserWizardModel() - { - Password = "a", - Username = "b" - }; +// private IdentityController Controller { get; set; } - var result = await Controller.CreateWizardUser(model); +// [Test] +// public async Task CreateWizardUser_Should_CreateUser_WhenThereAreNoOtherUsers() +// { +// var model = new CreateUserWizardModel() +// { +// Password = "a", +// Username = "b" +// }; - Assert.That(result, Is.True); - } +// var result = await Controller.CreateWizardUser(model); - [Test] - public async Task CreateWizardUser_ShouldNot_CreateUser_WhenThereAreOtherUsers() - { - var um = _serviceProvider.GetService(); - var r = await um.CreateAsync(new OmbiUser { UserName = "aaaa",UserType = UserType.LocalUser}, "bbb"); - var model = new CreateUserWizardModel - { - Password = "a", - Username = "b" - }; +// Assert.That(result, Is.True); +// } - var result = await Controller.CreateWizardUser(model); +// [Test] +// public async Task CreateWizardUser_ShouldNot_CreateUser_WhenThereAreOtherUsers() +// { +// var um = _serviceProvider.GetService(); +// var r = await um.CreateAsync(new OmbiUser { UserName = "aaaa",UserType = UserType.LocalUser}, "bbb"); +// var model = new CreateUserWizardModel +// { +// Password = "a", +// Username = "b" +// }; - Assert.That(result, Is.False); - } - } -} +// var result = await Controller.CreateWizardUser(model); + +// Assert.That(result, Is.False); +// } +// } +//} diff --git a/src/Ombi/ClientApp/app/app.component.html b/src/Ombi/ClientApp/app/app.component.html index 0db13fa9c..2f2c5a5a1 100644 --- a/src/Ombi/ClientApp/app/app.component.html +++ b/src/Ombi/ClientApp/app/app.component.html @@ -1,4 +1,4 @@ -
+