diff --git a/README.md b/README.md index 188c3baf0..73cb343c3 100644 --- a/README.md +++ b/README.md @@ -69,11 +69,11 @@ We are planning to bring back these features in V3 but for now you can find a li | Custom Notification Messages | Yes | No | | Sending newsletters | Planned | Yes | | Send a Mass Email | Planned | Yes | -| SickRage | Planned | Yes | +| SickRage | Yes | Yes | | CouchPotato | Yes | Yes | | Watcher | Planned | Yes | | DogNzb | Yes | No | -| Issues | Planned | Yes | +| Issues | Yes | Yes | | Headphones | No (support dropped) | Yes | # Feature Requests @@ -91,6 +91,7 @@ Search the existing requests to see if your suggestion has already been submitte # Installation [Click Here](https://github.com/tidusjar/Ombi/wiki/Installation) +[Here for Reverse Proxy Config Examples](https://github.com/tidusjar/Ombi/wiki/Nginx-Reverse-Proxy-examples-(Linux)) # Contributors diff --git a/build.cake b/build.cake index 807f79d73..8580d1fe4 100644 --- a/build.cake +++ b/build.cake @@ -95,6 +95,10 @@ Task("SetVersionInfo") { fullVer = buildVersion + "-PR"; } + if(fullVer.Contains("_")) + { + fullVer = fullVer.Replace("_",""); + } buildSettings.ArgumentCustomization = args => args.Append("/p:SemVer=" + versionInfo.AssemblySemVer); buildSettings.ArgumentCustomization = args => args.Append("/p:FullVer=" + fullVer); @@ -154,7 +158,6 @@ Task("Package") }); Task("Publish") - .IsDependentOn("Run-Unit-Tests") .IsDependentOn("PrePublish") .IsDependentOn("Publish-Windows") .IsDependentOn("Publish-OSX").IsDependentOn("Publish-Linux") @@ -204,12 +207,6 @@ Task("Publish-Linux") DotNetCorePublish("./src/Ombi.Updater/Ombi.Updater.csproj", publishSettings); }); -Task("Run-Unit-Tests") - .Does(() => -{ - DotNetCoreBuild(csProj, buildSettings); -}); - ////////////////////////////////////////////////////////////////////// // TASK TARGETS ////////////////////////////////////////////////////////////////////// diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index 77ba073d8..25e36666f 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -16,33 +16,18 @@ namespace Ombi.Api { public class Api : IApi { - public Api(ILogger log, ISettingsService s, IMemoryCache cache) + public Api(ILogger log, ISettingsService s, ICacheService cache, IOmbiHttpClient client) { Logger = log; _settings = s; _cache = cache; + _client = client; } private ILogger Logger { get; } private readonly ISettingsService _settings; - private readonly IMemoryCache _cache; - - private async Task GetHandler() - { - var settings = await _cache.GetOrCreateAsync(CacheKeys.OmbiSettings, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(1); - return await _settings.GetSettingsAsync(); - }); - if (settings.IgnoreCertificateErrors) - { - return new HttpClientHandler - { - ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true, - }; - } - return new HttpClientHandler(); - } + private readonly ICacheService _cache; + private readonly IOmbiHttpClient _client; private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { @@ -51,89 +36,82 @@ namespace Ombi.Api public async Task Request(Request request) { - using(var handler = await GetHandler()) - using (var httpClient = new HttpClient(handler)) + using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) { - using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) + // Add the Json Body + if (request.JsonBody != null) { - // Add the Json Body - if (request.JsonBody != null) - { - httpRequestMessage.Content = new JsonContent(request.JsonBody); - httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header - } + httpRequestMessage.Content = new JsonContent(request.JsonBody); + httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header + } - // Add headers - foreach (var header in request.Headers) - { - httpRequestMessage.Headers.Add(header.Key, header.Value); + // Add headers + foreach (var header in request.Headers) + { + httpRequestMessage.Headers.Add(header.Key, header.Value); - } - using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) + } + using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage)) + { + if (!httpResponseMessage.IsSuccessStatusCode) { - if (!httpResponseMessage.IsSuccessStatusCode) - { - Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); - } - // do something with the response - var data = httpResponseMessage.Content; - var receivedString = await data.ReadAsStringAsync(); - if (request.ContentType == ContentType.Json) - { - request.OnBeforeDeserialization?.Invoke(receivedString); - return JsonConvert.DeserializeObject(receivedString, Settings); - } - else - { - // XML - XmlSerializer serializer = new XmlSerializer(typeof(T)); - StringReader reader = new StringReader(receivedString); - var value = (T)serializer.Deserialize(reader); - return value; - } + Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); + } + // do something with the response + var data = httpResponseMessage.Content; + var receivedString = await data.ReadAsStringAsync(); + if (request.ContentType == ContentType.Json) + { + request.OnBeforeDeserialization?.Invoke(receivedString); + return JsonConvert.DeserializeObject(receivedString, Settings); + } + else + { + // XML + XmlSerializer serializer = new XmlSerializer(typeof(T)); + StringReader reader = new StringReader(receivedString); + var value = (T)serializer.Deserialize(reader); + return value; } } } + } public async Task RequestContent(Request request) { - using (var httpClient = new HttpClient(await GetHandler())) + using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) { - using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) + // Add the Json Body + if (request.JsonBody != null) { - // Add the Json Body - if (request.JsonBody != null) + httpRequestMessage.Content = new JsonContent(request.JsonBody); + } + + // Add headers + foreach (var header in request.Headers) + { + httpRequestMessage.Headers.Add(header.Key, header.Value); + + } + using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage)) + { + if (!httpResponseMessage.IsSuccessStatusCode) { - httpRequestMessage.Content = new JsonContent(request.JsonBody); + Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); } - - // Add headers - foreach (var header in request.Headers) - { - httpRequestMessage.Headers.Add(header.Key, header.Value); - - } - using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) - { - if (!httpResponseMessage.IsSuccessStatusCode) - { - Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); - } - // do something with the response - var data = httpResponseMessage.Content; + // do something with the response + var data = httpResponseMessage.Content; - return await data.ReadAsStringAsync(); - } + return await data.ReadAsStringAsync(); } } + } public async Task Request(Request request) { - using (var httpClient = new HttpClient(await GetHandler())) - { using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) { // Add the Json Body @@ -148,7 +126,7 @@ namespace Ombi.Api httpRequestMessage.Headers.Add(header.Key, header.Value); } - using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage)) + using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage)) { if (!httpResponseMessage.IsSuccessStatusCode) { @@ -156,7 +134,6 @@ namespace Ombi.Api } } } - } } } } diff --git a/src/Ombi.Api/IOmbiHttpClient.cs b/src/Ombi.Api/IOmbiHttpClient.cs new file mode 100644 index 000000000..6c2e22f7c --- /dev/null +++ b/src/Ombi.Api/IOmbiHttpClient.cs @@ -0,0 +1,10 @@ +using System.Net.Http; +using System.Threading.Tasks; + +namespace Ombi.Api +{ + public interface IOmbiHttpClient + { + Task SendAsync(HttpRequestMessage request); + } +} \ No newline at end of file diff --git a/src/Ombi.Api/OmbiHttpClient.cs b/src/Ombi.Api/OmbiHttpClient.cs new file mode 100644 index 000000000..ba21ddaa3 --- /dev/null +++ b/src/Ombi.Api/OmbiHttpClient.cs @@ -0,0 +1,86 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: OmbiHttpClient.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Ombi.Core.Settings; +using Ombi.Helpers; +using Ombi.Settings.Settings.Models; + +namespace Ombi.Api +{ + /// + /// The purpose of this class is simple, keep one instance of the HttpClient in play. + /// There are many articles related to when using multiple HttpClient's keeping the socket in a WAIT state + /// https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/ + /// https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ + /// + public class OmbiHttpClient : IOmbiHttpClient + { + public OmbiHttpClient(ICacheService cache, ISettingsService s) + { + _cache = cache; + _settings = s; + } + + private static HttpClient _client; + private static HttpMessageHandler _handler; + + private readonly ICacheService _cache; + private readonly ISettingsService _settings; + + + public async Task SendAsync(HttpRequestMessage request) + { + if (_client == null) + { + if (_handler == null) + { + // Get the handler + _handler = await GetHandler(); + } + _client = new HttpClient(_handler); + } + + return await _client.SendAsync(request); + } + + private async Task GetHandler() + { + var settings = await _cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await _settings.GetSettingsAsync(), DateTime.Now.AddHours(1)); + if (settings.IgnoreCertificateErrors) + { + return new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true, + }; + } + return new HttpClientHandler(); + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MovieSearchEngine.cs b/src/Ombi.Core/Engine/MovieSearchEngine.cs index db67bdee5..4e105d38d 100644 --- a/src/Ombi.Core/Engine/MovieSearchEngine.cs +++ b/src/Ombi.Core/Engine/MovieSearchEngine.cs @@ -19,7 +19,7 @@ namespace Ombi.Core.Engine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine { public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, - ILogger logger, IRuleEvaluator r, OmbiUserManager um, IMemoryCache mem) + ILogger logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem) : base(identity, service, r, um) { MovieApi = movApi; @@ -31,7 +31,7 @@ namespace Ombi.Core.Engine private IMovieDbApi MovieApi { get; } private IMapper Mapper { get; } private ILogger Logger { get; } - private IMemoryCache MemCache { get; } + private ICacheService MemCache { get; } /// /// Lookups the imdb information. @@ -69,11 +69,7 @@ namespace Ombi.Core.Engine /// public async Task> PopularMovies() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.PopularMovies, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await MovieApi.PopularMovies(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); @@ -88,11 +84,7 @@ namespace Ombi.Core.Engine /// public async Task> TopRatedMovies() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.TopRatedMovies, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await MovieApi.TopRated(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); @@ -107,11 +99,7 @@ namespace Ombi.Core.Engine /// public async Task> UpcomingMovies() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.UpcomingMovies, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await MovieApi.Upcoming(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.UpcomingMovies, async () => await MovieApi.Upcoming(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); @@ -126,11 +114,7 @@ namespace Ombi.Core.Engine /// public async Task> NowPlayingMovies() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.NowPlayingMovies, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await MovieApi.NowPlaying(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); diff --git a/src/Ombi.Core/Engine/TvSearchEngine.cs b/src/Ombi.Core/Engine/TvSearchEngine.cs index a5fb61426..2fc3e6c12 100644 --- a/src/Ombi.Core/Engine/TvSearchEngine.cs +++ b/src/Ombi.Core/Engine/TvSearchEngine.cs @@ -26,7 +26,7 @@ namespace Ombi.Core.Engine { public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService plexSettings, ISettingsService embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, - IMemoryCache memCache) + ICacheService memCache) : base(identity, service, r, um) { TvMazeApi = tvMaze; @@ -46,7 +46,7 @@ namespace Ombi.Core.Engine private IPlexContentRepository PlexContentRepo { get; } private IEmbyContentRepository EmbyContentRepo { get; } private ITraktApi TraktApi { get; } - private IMemoryCache MemCache { get; } + private ICacheService MemCache { get; } public async Task> Search(string searchTerm) { @@ -124,44 +124,28 @@ namespace Ombi.Core.Engine public async Task>> Popular() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.PopularTv, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await TraktApi.GetPopularShows(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12)); var processed = await ProcessResults(result); return processed.Select(ParseIntoTreeNode).ToList(); } public async Task>> Anticipated() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.AnticipatedTv, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await TraktApi.GetAnticipatedShows(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12)); var processed= await ProcessResults(result); return processed.Select(ParseIntoTreeNode).ToList(); } public async Task>> MostWatches() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.MostWatchesTv, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await TraktApi.GetMostWatchesShows(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12)); var processed = await ProcessResults(result); return processed.Select(ParseIntoTreeNode).ToList(); } public async Task>> Trending() { - var result = await MemCache.GetOrCreateAsync(CacheKeys.TrendingTv, async entry => - { - entry.AbsoluteExpiration = DateTimeOffset.Now.AddHours(12); - return await TraktApi.GetTrendingShows(); - }); + var result = await MemCache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12)); var processed = await ProcessResults(result); return processed.Select(ParseIntoTreeNode).ToList(); } diff --git a/src/Ombi.Core/Helpers/NotificationHelper.cs b/src/Ombi.Core/Helpers/NotificationHelper.cs index 02ff91b7d..9bd890c21 100644 --- a/src/Ombi.Core/Helpers/NotificationHelper.cs +++ b/src/Ombi.Core/Helpers/NotificationHelper.cs @@ -51,6 +51,7 @@ namespace Ombi.Core RequestType = model.RequestType, Recipient = model.RequestedUser?.Email ?? string.Empty }; + BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel)); } public void Notify(ChildRequests model, NotificationType type) diff --git a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs index ad8b1ea26..b3601fbe9 100644 --- a/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs +++ b/src/Ombi.Core/Helpers/TvShowRequestBuilder.cs @@ -52,7 +52,8 @@ namespace Ombi.Core.Helpers RequestedDate = DateTime.UtcNow, Approved = false, RequestedUserId = userId, - SeasonRequests = new List() + SeasonRequests = new List(), + Title = model.Title }; return this; diff --git a/src/Ombi.Core/Models/Requests/IssueState.cs b/src/Ombi.Core/Models/Requests/IssueState.cs deleted file mode 100644 index c44493c17..000000000 --- a/src/Ombi.Core/Models/Requests/IssueState.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ombi.Core.Models.Requests -{ - public enum IssueState - { - None = 99, - WrongAudio = 0, - NoSubtitles = 1, - WrongContent = 2, - PlaybackIssues = 3, - Other = 4 // Provide a message - } -} \ No newline at end of file diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index 8f61041c0..213c1744d 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -83,7 +83,10 @@ namespace Ombi.Core.Senders Success = true }; } - return new SenderResult(); + return new SenderResult + { + Message = "Could not send to SickRage!" + }; } return new SenderResult { diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 517290901..77350db40 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -86,6 +86,7 @@ namespace Ombi.DependencyInjection public static void RegisterApi(this IServiceCollection services) { services.AddTransient(); + services.AddSingleton(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/ services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -128,9 +129,10 @@ namespace Ombi.DependencyInjection public static void RegisterServices(this IServiceCollection services) { services.AddTransient(); - services.AddSingleton(); - services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); @@ -140,7 +142,6 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); - } public static void RegisterJobs(this IServiceCollection services) diff --git a/src/Ombi.Helpers/CacheService.cs b/src/Ombi.Helpers/CacheService.cs new file mode 100644 index 000000000..4eef62bda --- /dev/null +++ b/src/Ombi.Helpers/CacheService.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; +using Nito.AsyncEx; + +namespace Ombi.Helpers +{ + public class CacheService : ICacheService + { + private readonly IMemoryCache _memoryCache; + private readonly AsyncLock _mutex = new AsyncLock(); + public CacheService(IMemoryCache memoryCache) + { + _memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache)); + } + + public async Task GetOrAdd(string cacheKey, Func> factory, DateTime absoluteExpiration = default(DateTime)) + { + if (absoluteExpiration == default(DateTime)) + { + absoluteExpiration = DateTime.Now.AddHours(1); + } + // locks get and set internally + if (_memoryCache.TryGetValue(cacheKey, out var result)) + { + return result; + } + + using (await _mutex.LockAsync()) + { + if (_memoryCache.TryGetValue(cacheKey, out result)) + { + return result; + } + + result = await factory(); + _memoryCache.Set(cacheKey, result, absoluteExpiration); + + return result; + } + } + + public void Remove(string key) + { + _memoryCache.Remove(key); + } + + + + public T GetOrAdd(string cacheKey, Func factory, DateTime absoluteExpiration) + { + // locks get and set internally + if (_memoryCache.TryGetValue(cacheKey, out var result)) + { + return result; + } + + lock (TypeLock.Lock) + { + if (_memoryCache.TryGetValue(cacheKey, out result)) + { + return result; + } + + result = factory(); + _memoryCache.Set(cacheKey, result, absoluteExpiration); + + return result; + } + } + + private static class TypeLock + { + public static object Lock { get; } = new object(); + } + + } +} diff --git a/src/Ombi.Helpers/ICacheService.cs b/src/Ombi.Helpers/ICacheService.cs new file mode 100644 index 000000000..8c20d2d23 --- /dev/null +++ b/src/Ombi.Helpers/ICacheService.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; + +namespace Ombi.Helpers +{ + public interface ICacheService + { + Task GetOrAdd(string cacheKey, Func> factory, DateTime absoluteExpiration = default(DateTime)); + T GetOrAdd(string cacheKey, Func factory, DateTime absoluteExpiration); + void Remove(string key); + } +} \ No newline at end of file diff --git a/src/Ombi.Helpers/MemoryCacheHelper.cs b/src/Ombi.Helpers/MemoryCacheHelper.cs deleted file mode 100644 index 2c8c429fd..000000000 --- a/src/Ombi.Helpers/MemoryCacheHelper.cs +++ /dev/null @@ -1,54 +0,0 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2017 Jamie Rees -// File: MemoryCacheHelper.cs -// Created By: Jamie Rees -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ************************************************************************/ -#endregion - - -using System; -using Microsoft.Extensions.Caching.Memory; - -namespace Ombi.Helpers -{ - public static class MemoryCacheHelper - { - public static IMemoryCache TryAdd(this IMemoryCache cache, object cacheObject, TimeSpan slidingExpiration) - { - object cachedObject; - if (!cache.TryGetValue(CacheKeys.Update, out cachedObject)) - { - // Key not in cache, so get data. - - // Set cache options. - var cacheEntryOptions = new MemoryCacheEntryOptions() - .SetSlidingExpiration(slidingExpiration); - - // Save data in cache. - cache.Set(CacheKeys.Update, cacheObject, cacheEntryOptions); - } - - return cache; - } - } -} \ No newline at end of file diff --git a/src/Ombi.Helpers/Ombi.Helpers.csproj b/src/Ombi.Helpers/Ombi.Helpers.csproj index 080ed0f8a..d9ef54efa 100644 --- a/src/Ombi.Helpers/Ombi.Helpers.csproj +++ b/src/Ombi.Helpers/Ombi.Helpers.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Ombi.Notifications.Templates/Templates/BasicTemplate.html b/src/Ombi.Notifications.Templates/Templates/BasicTemplate.html index 63b86e125..8482b6b40 100644 --- a/src/Ombi.Notifications.Templates/Templates/BasicTemplate.html +++ b/src/Ombi.Notifications.Templates/Templates/BasicTemplate.html @@ -144,7 +144,7 @@ @@ -155,7 +155,7 @@
- + Ombi logo
- + Poster
diff --git a/src/Ombi.Notifications/Agents/EmailNotification.cs b/src/Ombi.Notifications/Agents/EmailNotification.cs index 8c42a82d6..123aa1e99 100644 --- a/src/Ombi.Notifications/Agents/EmailNotification.cs +++ b/src/Ombi.Notifications/Agents/EmailNotification.cs @@ -71,6 +71,13 @@ namespace Ombi.Notifications.Agents return message; } + private async Task LoadPlainTextMessage(NotificationType type, NotificationOptions model, EmailNotificationSettings settings) + { + var parsed = await LoadTemplate(NotificationAgent.Email, type, model); + + return parsed.Message; + } + protected override async Task NewRequest(NotificationOptions model, EmailNotificationSettings settings) { var message = await LoadTemplate(NotificationType.NewRequest, model, settings); @@ -78,7 +85,10 @@ namespace Ombi.Notifications.Agents { return; } - + + var plaintext = await LoadPlainTextMessage(NotificationType.NewRequest, model, settings); + message.Other.Add("PlainTextBody", plaintext); + await Send(message, settings); } @@ -89,7 +99,13 @@ namespace Ombi.Notifications.Agents { return; } - + + var plaintext = await LoadPlainTextMessage(NotificationType.Issue, model, settings); + message.Other.Add("PlainTextBody", plaintext); + + // Issues should be sent to admin + message.To = settings.AdminEmail; + await Send(message, settings); } @@ -122,7 +138,10 @@ namespace Ombi.Notifications.Agents Subject = $"{Customization.ApplicationName}: A request could not be added", To = settings.AdminEmail, }; - + + var plaintext = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying"; + message.Other.Add("PlainTextBody", plaintext); + await Send(message, settings); } @@ -133,6 +152,10 @@ namespace Ombi.Notifications.Agents { return; } + + var plaintext = await LoadPlainTextMessage(NotificationType.RequestDeclined, model, settings); + message.Other.Add("PlainTextBody", plaintext); + message.To = model.RequestType == RequestType.Movie ? MovieRequest.RequestedUser.Email : TvRequest.RequestedUser.Email; @@ -146,6 +169,10 @@ namespace Ombi.Notifications.Agents { return; } + + var plaintext = await LoadPlainTextMessage(NotificationType.RequestApproved, model, settings); + message.Other.Add("PlainTextBody", plaintext); + message.To = model.RequestType == RequestType.Movie ? MovieRequest.RequestedUser.Email : TvRequest.RequestedUser.Email; @@ -159,6 +186,10 @@ namespace Ombi.Notifications.Agents { return; } + + var plaintext = await LoadPlainTextMessage(NotificationType.RequestAvailable, model, settings); + message.Other.Add("PlainTextBody", plaintext); + message.To = model.RequestType == RequestType.Movie ? MovieRequest.RequestedUser.Email : TvRequest.RequestedUser.Email; diff --git a/src/Ombi.Notifications/GenericEmailProvider.cs b/src/Ombi.Notifications/GenericEmailProvider.cs index b5979d9aa..4a425c4af 100644 --- a/src/Ombi.Notifications/GenericEmailProvider.cs +++ b/src/Ombi.Notifications/GenericEmailProvider.cs @@ -40,7 +40,7 @@ namespace Ombi.Notifications var body = new BodyBuilder { HtmlBody = html, - //TextBody = model.Other["PlainTextBody"] + TextBody = model.Other["PlainTextBody"] }; var message = new MimeMessage @@ -104,7 +104,7 @@ namespace Ombi.Notifications var body = new BodyBuilder { HtmlBody = model.Message, - //TextBody = model.Other["PlainTextBody"] + TextBody = model.Other["PlainTextBody"] }; var message = new MimeMessage diff --git a/src/Ombi.Notifications/Interfaces/BaseNotification.cs b/src/Ombi.Notifications/Interfaces/BaseNotification.cs index bc681ceed..f7c44425a 100644 --- a/src/Ombi.Notifications/Interfaces/BaseNotification.cs +++ b/src/Ombi.Notifications/Interfaces/BaseNotification.cs @@ -60,6 +60,7 @@ namespace Ombi.Notifications.Interfaces // Is this a test? // The request id for tests is -1 + // Also issues are 0 since there might not be a request associated if (model.RequestId > 0) { await LoadRequest(model.RequestId, model.RequestType); @@ -157,11 +158,11 @@ namespace Ombi.Notifications.Interfaces var curlys = new NotificationMessageCurlys(); if (model.RequestType == RequestType.Movie) { - curlys.Setup(MovieRequest, Customization); + curlys.Setup(model, MovieRequest, Customization); } else { - curlys.Setup(TvRequest, Customization); + curlys.Setup(model, TvRequest, Customization); } var parsed = resolver.ParseMessage(template, curlys); diff --git a/src/Ombi.Notifications/Models/NotificationOptions.cs b/src/Ombi.Notifications/Models/NotificationOptions.cs index bfcb4a85a..80d619083 100644 --- a/src/Ombi.Notifications/Models/NotificationOptions.cs +++ b/src/Ombi.Notifications/Models/NotificationOptions.cs @@ -12,5 +12,7 @@ namespace Ombi.Notifications.Models public NotificationType NotificationType { get; set; } public RequestType RequestType { get; set; } public string Recipient { get; set; } + public string AdditionalInformation { get; set; } + } } \ No newline at end of file diff --git a/src/Ombi.Notifications/NotificationMessageCurlys.cs b/src/Ombi.Notifications/NotificationMessageCurlys.cs index 86e1f724d..29aa87f0a 100644 --- a/src/Ombi.Notifications/NotificationMessageCurlys.cs +++ b/src/Ombi.Notifications/NotificationMessageCurlys.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Ombi.Notifications.Models; using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; @@ -9,7 +10,7 @@ namespace Ombi.Notifications public class NotificationMessageCurlys { - public void Setup(FullBaseRequest req, CustomizationSettings s) + public void Setup(NotificationOptions opts, FullBaseRequest req, CustomizationSettings s) { ApplicationUrl = s.ApplicationUrl; ApplicationName = string.IsNullOrEmpty(s.ApplicationName) ? "Ombi" : s.ApplicationName; @@ -23,9 +24,10 @@ namespace Ombi.Notifications Year = req.ReleaseDate.Year.ToString(); PosterImage = req.RequestType == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300{req.PosterPath}" : req.PosterPath; + AdditionalInformation = opts.AdditionalInformation; } - public void Setup(ChildRequests req, CustomizationSettings s) + public void Setup(NotificationOptions opts, ChildRequests req, CustomizationSettings s) { ApplicationUrl = s.ApplicationUrl; ApplicationName = string.IsNullOrEmpty(s.ApplicationName) ? "Ombi" : s.ApplicationName; @@ -39,6 +41,7 @@ namespace Ombi.Notifications Year = req.ParentRequest.ReleaseDate.Year.ToString(); PosterImage = req.RequestType == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300{req.ParentRequest.PosterPath}" : req.ParentRequest.PosterPath; + AdditionalInformation = opts.AdditionalInformation; // DO Episode and Season Lists } @@ -54,7 +57,7 @@ namespace Ombi.Notifications public string Title { get; set; } public string RequestedDate { get; set; } public string Type { get; set; } - public string Issue { get; set; } + public string AdditionalInformation { get; set; } public string Overview { get; set; } public string Year { get; set; } public string EpisodesList { get; set; } @@ -75,7 +78,7 @@ namespace Ombi.Notifications {nameof(Title), Title }, {nameof(RequestedDate), RequestedDate }, {nameof(Type), Type }, - {nameof(Issue), Issue }, + {nameof(AdditionalInformation), AdditionalInformation }, {nameof(LongDate),LongDate}, {nameof(ShortDate),ShortDate}, {nameof(LongTime),LongTime}, diff --git a/src/Ombi.Notifications/NotificationService.cs b/src/Ombi.Notifications/NotificationService.cs index 53bb23bd6..d76f38e69 100644 --- a/src/Ombi.Notifications/NotificationService.cs +++ b/src/Ombi.Notifications/NotificationService.cs @@ -67,7 +67,7 @@ namespace Ombi.Notifications /// The model. /// The settings. /// - public async Task Publish(NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings) + public async Task Publish(NotificationOptions model, Settings.Settings.Models.Settings settings) { var notificationTasks = NotificationAgents.Select(notification => NotifyAsync(notification, model, settings)); diff --git a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs index 5794ac16e..23d85e0d2 100644 --- a/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Radarr/RadarrSync.cs @@ -37,7 +37,7 @@ namespace Ombi.Schedule.Jobs.Radarr await SemaphoreSlim.WaitAsync(); try { - var settings = RadarrSettings.GetSettings(); + var settings = await RadarrSettings.GetSettingsAsync(); if (settings.Enabled) { try diff --git a/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs b/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs index 041783cfd..5cfececd4 100644 --- a/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs +++ b/src/Ombi.Schedule/Jobs/Sonarr/SonarrSync.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.Logging; using Ombi.Api.Sonarr; using Ombi.Api.Sonarr.Models; using Ombi.Core.Settings; -using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Settings.Settings.Models.External; using Ombi.Store.Context; @@ -53,22 +52,25 @@ namespace Ombi.Schedule.Jobs.Sonarr var entites = ids.Select(id => new SonarrCache { TvDbId = id }).ToList(); await _ctx.SonarrCache.AddRangeAsync(entites); - - var episodesToAdd = new List(); + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrEpisodeCache"); foreach (var s in sonarrSeries) { + _log.LogDebug("Syncing series: {0}", s.title); var episodes = await _api.GetEpisodes(s.id, settings.ApiKey, settings.FullUri); var monitoredEpisodes = episodes.Where(x => x.monitored || x.hasFile); - episodesToAdd.AddRange(monitoredEpisodes.Select(episode => new SonarrEpisodeCache + + // Add to DB + _log.LogDebug("We have the episodes, adding to db transaction"); + await _ctx.SonarrEpisodeCache.AddRangeAsync(monitoredEpisodes.Select(episode => new SonarrEpisodeCache { EpisodeNumber = episode.episodeNumber, SeasonNumber = episode.seasonNumber, TvDbId = s.tvdbId })); } - - await _ctx.SonarrEpisodeCache.AddRangeAsync(episodesToAdd); + + _log.LogDebug("Commiting the transaction"); await _ctx.SaveChangesAsync(); } } @@ -81,58 +83,5 @@ namespace Ombi.Schedule.Jobs.Sonarr SemaphoreSlim.Release(); } } - - - //public void Queued() - //{ - // var settings = SonarrSettings.GetSettings(); - // if (settings.Enabled) - // { - // Job.SetRunning(true, JobNames.SonarrCacher); - // try - // { - // var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri); - // if (series != null) - // { - // Cache.Set(CacheKeys.SonarrQueued, series, CacheKeys.TimeFrameMinutes.SchedulerCaching); - // } - // } - // catch (System.Exception ex) - // { - // Log.Error(ex, "Failed caching queued items from Sonarr"); - // } - // finally - // { - // Job.Record(JobNames.SonarrCacher); - // Job.SetRunning(false, JobNames.SonarrCacher); - // } - // } - //} - - //// we do not want to set here... - //public IEnumerable QueuedIds() - //{ - // var result = new List(); - - // var series = Cache.Get>(CacheKeys.SonarrQueued); - // if (series != null) - // { - // foreach (var s in series) - // { - // var cached = new SonarrCachedResult { TvdbId = s.tvdbId }; - // foreach (var season in s.seasons) - // { - // cached.Seasons.Add(new SonarrSeasons - // { - // SeasonNumber = season.seasonNumber, - // Monitored = season.monitored - // }); - // } - - // result.Add(cached); - // } - // } - // return result; - //} } } \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/IssueSettings.cs b/src/Ombi.Settings/Settings/Models/IssueSettings.cs new file mode 100644 index 000000000..e025c82d1 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/IssueSettings.cs @@ -0,0 +1,8 @@ +namespace Ombi.Settings.Settings.Models +{ + public class IssueSettings : Settings + { + public bool Enabled { get; set; } + public bool EnableInProgress { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/SettingsService.cs b/src/Ombi.Settings/Settings/SettingsService.cs index 5cba10522..e5c5409a2 100644 --- a/src/Ombi.Settings/Settings/SettingsService.cs +++ b/src/Ombi.Settings/Settings/SettingsService.cs @@ -5,7 +5,6 @@ using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Store.Entities; using Ombi.Store.Repository; -using Microsoft.Extensions.Caching.Memory; namespace Ombi.Settings.Settings { @@ -13,7 +12,7 @@ namespace Ombi.Settings.Settings where T : Models.Settings, new() { - public SettingsService(ISettingsRepository repo, IMemoryCache cache) + public SettingsService(ISettingsRepository repo, ICacheService cache) { Repo = repo; EntityName = typeof(T).Name; @@ -23,13 +22,12 @@ namespace Ombi.Settings.Settings private ISettingsRepository Repo { get; } private string EntityName { get; } private string CacheName => $"Settings{EntityName}"; - private readonly IMemoryCache _cache; + private readonly ICacheService _cache; public T GetSettings() { - return _cache.GetOrCreate(CacheName, entry => + return _cache.GetOrAdd(CacheName, () => { - entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2); var result = Repo.Get(EntityName); if (result == null) { @@ -43,14 +41,13 @@ namespace Ombi.Settings.Settings var model = obj; return model; - }); + }, DateTime.Now.AddHours(2)); } public async Task GetSettingsAsync() { - return await _cache.GetOrCreateAsync(CacheName, async entry => + return await _cache.GetOrAdd(CacheName, async () => { - entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2); var result = await Repo.GetAsync(EntityName); if (result == null) { @@ -64,7 +61,7 @@ namespace Ombi.Settings.Settings var model = obj; return model; - }); + }, DateTime.Now.AddHours(2)); } public bool SaveSettings(T model) diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs index 1fa5c38fd..64f23669e 100644 --- a/src/Ombi.Store/Context/IOmbiContext.cs +++ b/src/Ombi.Store/Context/IOmbiContext.cs @@ -30,8 +30,8 @@ namespace Ombi.Store.Context DbSet MovieRequests { get; set; } DbSet TvRequests { get; set; } DbSet ChildRequests { get; set; } - DbSet MovieIssues { get; set; } - DbSet TvIssues { get; set; } + DbSet Issues { get; set; } + DbSet IssueCategories { get; set; } DbSet Tokens { get; set; } DbSet SonarrCache { get; set; } DbSet SonarrEpisodeCache { get; set; } diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index 3651bfd64..edf21009e 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -33,10 +33,13 @@ namespace Ombi.Store.Context public DbSet MovieRequests { get; set; } public DbSet TvRequests { get; set; } public DbSet ChildRequests { get; set; } - public DbSet MovieIssues { get; set; } - public DbSet TvIssues { get; set; } + + public DbSet Issues { get; set; } + public DbSet IssueCategories { get; set; } + public DbSet IssueComments { get; set; } public DbSet RequestLogs { get; set; } + public DbSet Audit { get; set; } public DbSet Tokens { get; set; } public DbSet SonarrCache { get; set; } diff --git a/src/Ombi.Store/Entities/Requests/ChildRequests.cs b/src/Ombi.Store/Entities/Requests/ChildRequests.cs index 38b5e884f..dad96538f 100644 --- a/src/Ombi.Store/Entities/Requests/ChildRequests.cs +++ b/src/Ombi.Store/Entities/Requests/ChildRequests.cs @@ -14,7 +14,7 @@ namespace Ombi.Store.Entities.Requests [ForeignKey(nameof(IssueId))] - public List Issues { get; set; } + public List Issues { get; set; } public List SeasonRequests { get; set; } } diff --git a/src/Ombi.Store/Entities/Requests/IssueCategory.cs b/src/Ombi.Store/Entities/Requests/IssueCategory.cs new file mode 100644 index 000000000..652008fbc --- /dev/null +++ b/src/Ombi.Store/Entities/Requests/IssueCategory.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities.Requests +{ + [Table("IssueCategory")] + public class IssueCategory : Entity + { + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/IssueComments.cs b/src/Ombi.Store/Entities/Requests/IssueComments.cs new file mode 100644 index 000000000..c37adf34a --- /dev/null +++ b/src/Ombi.Store/Entities/Requests/IssueComments.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities.Requests +{ + public class IssueComments : Entity + { + public string UserId { get; set; } + public string Comment { get; set; } + public int? IssuesId { get; set; } + public DateTime Date { get; set; } + + [ForeignKey(nameof(IssuesId))] + public Issues Issues{ get; set; } + [ForeignKey(nameof(UserId))] + public OmbiUser User { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/Issues.cs b/src/Ombi.Store/Entities/Requests/Issues.cs new file mode 100644 index 000000000..b1021e362 --- /dev/null +++ b/src/Ombi.Store/Entities/Requests/Issues.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities.Requests +{ + [Table("Issues")] + public class Issues : Entity + { + public string Title { get; set; } + public RequestType RequestType { get; set; } + public string ProviderId { get; set; } + public int? RequestId { get; set; } + public string Subject { get; set; } + public string Description { get; set; } + public int IssueCategoryId { get; set; } + [ForeignKey(nameof(IssueCategoryId))] + public IssueCategory IssueCategory { get; set; } + public IssueStatus Status { get; set; } + public DateTime? ResovledDate { get; set; } + [ForeignKey(nameof(UserReported))] + public string UserReportedId { get; set; } + public OmbiUser UserReported { get; set; } + public List Comments { get; set; } + } + + public enum IssueStatus + { + Pending = 0, + InProgress = 1, + Resolved = 2, + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/IssuesBase.cs b/src/Ombi.Store/Entities/Requests/IssuesBase.cs deleted file mode 100644 index 53ef2d6da..000000000 --- a/src/Ombi.Store/Entities/Requests/IssuesBase.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ombi.Store.Entities.Requests -{ - public class IssuesBase : Entity - { - public string Subect { get; set; } - public string Description { get; set; } - - } -} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/MovieIssues.cs b/src/Ombi.Store/Entities/Requests/MovieIssues.cs deleted file mode 100644 index 2f93ff42f..000000000 --- a/src/Ombi.Store/Entities/Requests/MovieIssues.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; - -namespace Ombi.Store.Entities.Requests -{ - [Table("MovieIssues")] - public class MovieIssues : IssuesBase - { - public int MovieId { get; set; } - [ForeignKey(nameof(MovieId))] - public MovieRequests Movie { get; set; } - } -} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/MovieRequests.cs b/src/Ombi.Store/Entities/Requests/MovieRequests.cs index 680a1c8bb..998c27707 100644 --- a/src/Ombi.Store/Entities/Requests/MovieRequests.cs +++ b/src/Ombi.Store/Entities/Requests/MovieRequests.cs @@ -10,7 +10,7 @@ namespace Ombi.Store.Entities.Requests public int TheMovieDbId { get; set; } public int? IssueId { get; set; } [ForeignKey(nameof(IssueId))] - public List Issues { get; set; } + public List Issues { get; set; } public int RootPathOverride { get; set; } public int QualityOverride { get; set; } diff --git a/src/Ombi.Store/Entities/Requests/TvIssues.cs b/src/Ombi.Store/Entities/Requests/TvIssues.cs deleted file mode 100644 index aefede5d6..000000000 --- a/src/Ombi.Store/Entities/Requests/TvIssues.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.ComponentModel.DataAnnotations.Schema; - -namespace Ombi.Store.Entities.Requests -{ - [Table("TvIssues")] - public class TvIssues : IssuesBase - { - public int TvId { get; set; } - [ForeignKey(nameof(TvId))] - public ChildRequests Child { get; set; } - } -} \ No newline at end of file diff --git a/src/Ombi.Store/Migrations/20171103003202_Inital.Designer.cs b/src/Ombi.Store/Migrations/20171103003202_Inital.Designer.cs index 3bde0f01c..5c6dcc28a 100644 --- a/src/Ombi.Store/Migrations/20171103003202_Inital.Designer.cs +++ b/src/Ombi.Store/Migrations/20171103003202_Inital.Designer.cs @@ -447,7 +447,7 @@ namespace Ombi.Store.Migrations b.Property("MovieId"); - b.Property("Subect"); + b.Property("Subject"); b.HasKey("Id"); @@ -513,7 +513,7 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); - b.Property("Subect"); + b.Property("Subject"); b.Property("TvId"); diff --git a/src/Ombi.Store/Migrations/20171103003202_Inital.cs b/src/Ombi.Store/Migrations/20171103003202_Inital.cs index 77eb681d1..b4efb8fd7 100644 --- a/src/Ombi.Store/Migrations/20171103003202_Inital.cs +++ b/src/Ombi.Store/Migrations/20171103003202_Inital.cs @@ -504,7 +504,7 @@ namespace Ombi.Store.Migrations Description = table.Column(type: "TEXT", nullable: true), IssueId = table.Column(type: "INTEGER", nullable: true), MovieId = table.Column(type: "INTEGER", nullable: false), - Subect = table.Column(type: "TEXT", nullable: true) + Subject = table.Column(type: "TEXT", nullable: true) }, constraints: table => { @@ -551,7 +551,7 @@ namespace Ombi.Store.Migrations .Annotation("Sqlite:Autoincrement", true), Description = table.Column(type: "TEXT", nullable: true), IssueId = table.Column(type: "INTEGER", nullable: true), - Subect = table.Column(type: "TEXT", nullable: true), + Subject = table.Column(type: "TEXT", nullable: true), TvId = table.Column(type: "INTEGER", nullable: false) }, constraints: table => diff --git a/src/Ombi.Store/Migrations/20171103224757_MovieBackground.Designer.cs b/src/Ombi.Store/Migrations/20171103224757_MovieBackground.Designer.cs index f57a8d8ab..f7baa434e 100644 --- a/src/Ombi.Store/Migrations/20171103224757_MovieBackground.Designer.cs +++ b/src/Ombi.Store/Migrations/20171103224757_MovieBackground.Designer.cs @@ -447,7 +447,7 @@ namespace Ombi.Store.Migrations b.Property("MovieId"); - b.Property("Subect"); + b.Property("Subject"); b.HasKey("Id"); @@ -515,7 +515,7 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); - b.Property("Subect"); + b.Property("Subject"); b.Property("TvId"); diff --git a/src/Ombi.Store/Migrations/20171123144147_EmbyConnectUser.Designer.cs b/src/Ombi.Store/Migrations/20171123144147_EmbyConnectUser.Designer.cs index 3305aa261..4c92a7cef 100644 --- a/src/Ombi.Store/Migrations/20171123144147_EmbyConnectUser.Designer.cs +++ b/src/Ombi.Store/Migrations/20171123144147_EmbyConnectUser.Designer.cs @@ -449,7 +449,7 @@ namespace Ombi.Store.Migrations b.Property("MovieId"); - b.Property("Subect"); + b.Property("Subject"); b.HasKey("Id"); @@ -517,7 +517,7 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); - b.Property("Subect"); + b.Property("Subject"); b.Property("TvId"); diff --git a/src/Ombi.Store/Migrations/20171128081222_SickRage.Designer.cs b/src/Ombi.Store/Migrations/20171128081222_SickRage.Designer.cs index c2d64c2dc..6a767c246 100644 --- a/src/Ombi.Store/Migrations/20171128081222_SickRage.Designer.cs +++ b/src/Ombi.Store/Migrations/20171128081222_SickRage.Designer.cs @@ -449,7 +449,7 @@ namespace Ombi.Store.Migrations b.Property("MovieId"); - b.Property("Subect"); + b.Property("Subject"); b.HasKey("Id"); @@ -517,7 +517,7 @@ namespace Ombi.Store.Migrations b.Property("IssueId"); - b.Property("Subect"); + b.Property("Subject"); b.Property("TvId"); diff --git a/src/Ombi.Store/Migrations/20171213154624_Issues.Designer.cs b/src/Ombi.Store/Migrations/20171213154624_Issues.Designer.cs new file mode 100644 index 000000000..5f5c75e74 --- /dev/null +++ b/src/Ombi.Store/Migrations/20171213154624_Issues.Designer.cs @@ -0,0 +1,840 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using Ombi.Helpers; +using Ombi.Store.Context; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using System; + +namespace Ombi.Store.Migrations +{ + [DbContext(typeof(OmbiContext))] + [Migration("20171213154624_Issues")] + partial class Issues + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider"); + + b.Property("ProviderKey"); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider"); + + b.Property("Name"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Type"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("ApplicationConfiguration"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditArea"); + + b.Property("AuditType"); + + b.Property("DateTime"); + + b.Property("Description"); + + b.Property("User"); + + b.HasKey("Id"); + + b.ToTable("Audit"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("CouchPotatoCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId") + .IsRequired(); + + b.Property("ProviderId"); + + b.Property("Title"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId"); + + b.Property("EpisodeNumber"); + + b.Property("ParentId"); + + b.Property("ProviderId"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Content"); + + b.Property("SettingsName"); + + b.HasKey("Id"); + + b.ToTable("GlobalSettings"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Agent"); + + b.Property("Enabled"); + + b.Property("Message"); + + b.Property("NotificationType"); + + b.Property("Subject"); + + b.HasKey("Id"); + + b.ToTable("NotificationTemplates"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("Alias"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("EmbyConnectUserId"); + + b.Property("LastLoggedIn"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("ProviderUserId"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("UserType"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("GrandparentKey"); + + b.Property("Key"); + + b.Property("ParentKey"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ParentKey"); + + b.Property("PlexContentId"); + + b.Property("PlexServerContentId"); + + b.Property("SeasonKey"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("PlexServerContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("ImdbId"); + + b.Property("Key"); + + b.Property("Quality"); + + b.Property("ReleaseYear"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.Property("Type"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.ToTable("PlexServerContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("IssueId"); + + b.Property("ParentRequestId"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentRequestId"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("ChildRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("IssueCategory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Comment"); + + b.Property("Date"); + + b.Property("IssuesId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("IssuesId"); + + b.HasIndex("UserId"); + + b.ToTable("IssueComments"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueCategoryId"); + + b.Property("IssueId"); + + b.Property("ProviderId"); + + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("ResovledDate"); + + b.Property("Status"); + + b.Property("Subject"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("IssueCategoryId"); + + b.HasIndex("IssueId"); + + b.ToTable("Issues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Background"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("ImdbId"); + + b.Property("IssueId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + b.Property("ReleaseDate"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("RootPathOverride"); + + b.Property("Status"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("MovieRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ImdbId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("ReleaseDate"); + + b.Property("RootFolder"); + + b.Property("Status"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("TvRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SickRageEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("SeasonNumber"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrEpisodeCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AirDate"); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("EpisodeNumber"); + + b.Property("Requested"); + + b.Property("SeasonId"); + + b.Property("Title"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("EpisodeRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChildRequestId"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("ChildRequestId"); + + b.ToTable("SeasonRequests"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexServerContent") + .WithMany("Seasons") + .HasForeignKey("PlexServerContentId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest") + .WithMany("ChildRequests") + .HasForeignKey("ParentRequestId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues") + .WithMany("Comments") + .HasForeignKey("IssuesId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory") + .WithMany() + .HasForeignKey("IssueCategoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest") + .WithMany("SeasonRequests") + .HasForeignKey("ChildRequestId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/20171213154624_Issues.cs b/src/Ombi.Store/Migrations/20171213154624_Issues.cs new file mode 100644 index 000000000..6582e7605 --- /dev/null +++ b/src/Ombi.Store/Migrations/20171213154624_Issues.cs @@ -0,0 +1,138 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace Ombi.Store.Migrations +{ + public partial class Issues : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "IssueCategory", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Value = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IssueCategory", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Issues", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Description = table.Column(type: "TEXT", nullable: true), + IssueCategoryId = table.Column(type: "INTEGER", nullable: false), + IssueId = table.Column(type: "INTEGER", nullable: true), + ProviderId = table.Column(type: "TEXT", nullable: true), + RequestId = table.Column(type: "INTEGER", nullable: true), + RequestType = table.Column(type: "INTEGER", nullable: false), + ResovledDate = table.Column(type: "TEXT", nullable: true), + Status = table.Column(type: "INTEGER", nullable: false), + Subject = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + UserReportedId = table.Column(type: "TEXT", nullable: true), + }, + constraints: table => + { + table.PrimaryKey("PK_Issues", x => x.Id); + table.ForeignKey( + name: "FK_Issues_IssueCategory_IssueCategoryId", + column: x => x.IssueCategoryId, + principalTable: "IssueCategory", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Issues_ChildRequests_IssueId", + column: x => x.IssueId, + principalTable: "ChildRequests", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Issues_MovieRequests_IssueId", + column: x => x.IssueId, + principalTable: "MovieRequests", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Issues_AspNetUsers_UserReportedId", + column: x => x.UserReportedId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "IssueComments", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Comment = table.Column(type: "TEXT", nullable: true), + Date = table.Column(type: "TEXT", nullable: false), + IssuesId = table.Column(type: "INTEGER", nullable: true), + UserId = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IssueComments", x => x.Id); + table.ForeignKey( + name: "FK_IssueComments_Issues_IssuesId", + column: x => x.IssuesId, + principalTable: "Issues", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_IssueComments_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_IssueComments_IssuesId", + table: "IssueComments", + column: "IssuesId"); + + migrationBuilder.CreateIndex( + name: "IX_IssueComments_UserId", + table: "IssueComments", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Issues_IssueCategoryId", + table: "Issues", + column: "IssueCategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_Issues_IssueId", + table: "Issues", + column: "IssueId"); + + migrationBuilder.CreateIndex( + name: "IX_Issues_UserReportedId", + table: "Issues", + column: "UserReportedId"); + + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "IssueComments"); + + migrationBuilder.DropTable( + name: "Issues"); + + migrationBuilder.DropTable( + name: "IssueCategory"); + } + } +} diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs index b920fda1e..0258dd8c0 100644 --- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore.Storage.Internal; using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; using System; namespace Ombi.Store.Migrations @@ -441,26 +442,76 @@ namespace Ombi.Store.Migrations b.ToTable("ChildRequests"); }); - modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("IssueCategory"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Comment"); + + b.Property("Date"); + + b.Property("IssuesId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("IssuesId"); + + b.HasIndex("UserId"); + + b.ToTable("IssueComments"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => { b.Property("Id") .ValueGeneratedOnAdd(); b.Property("Description"); + b.Property("IssueCategoryId"); + b.Property("IssueId"); - b.Property("MovieId"); + b.Property("ProviderId"); - b.Property("Subect"); + b.Property("RequestId"); + + b.Property("RequestType"); + + b.Property("ResovledDate"); + + b.Property("Status"); + + b.Property("Subject"); + + b.Property("Title"); + + b.Property("UserReportedId"); b.HasKey("Id"); + b.HasIndex("IssueCategoryId"); + b.HasIndex("IssueId"); - b.HasIndex("MovieId"); + b.HasIndex("UserReportedId"); - b.ToTable("MovieIssues"); + b.ToTable("Issues"); }); modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => @@ -533,28 +584,6 @@ namespace Ombi.Store.Migrations b.ToTable("RequestLog"); }); - modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("Description"); - - b.Property("IssueId"); - - b.Property("Subect"); - - b.Property("TvId"); - - b.HasKey("Id"); - - b.HasIndex("IssueId"); - - b.HasIndex("TvId"); - - b.ToTable("TvIssues"); - }); - modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => { b.Property("Id") @@ -778,23 +807,34 @@ namespace Ombi.Store.Migrations .HasForeignKey("RequestedUserId"); }); - modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b => { + b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues") + .WithMany("Comments") + .HasForeignKey("IssuesId"); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory") + .WithMany() + .HasForeignKey("IssueCategoryId") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") .WithMany("Issues") .HasForeignKey("IssueId"); - b.HasOne("Ombi.Store.Entities.Requests.MovieRequests", "Movie") + b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported") .WithMany() - .HasForeignKey("MovieId") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => - { - b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") - .WithMany() - .HasForeignKey("RequestedUserId"); + .HasForeignKey("UserReportedId"); }); modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b => @@ -803,17 +843,13 @@ namespace Ombi.Store.Migrations .WithMany() .HasForeignKey("UserId"); }); + - modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => { - b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") - .WithMany("Issues") - .HasForeignKey("IssueId"); - - b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "Child") + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") .WithMany() - .HasForeignKey("TvId") - .OnDelete(DeleteBehavior.Cascade); + .HasForeignKey("RequestedUserId"); }); modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => diff --git a/src/Ombi.Store/Repository/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index 4996eac0b..87d811e5d 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -7,7 +7,6 @@ namespace Ombi.Store.Repository { public interface IPlexContentRepository : IRepository { - Task Add(PlexServerContent content); Task ContentExists(string providerId); Task Get(string providerId); Task GetByKey(int key); diff --git a/src/Ombi.Store/Repository/IRepository.cs b/src/Ombi.Store/Repository/IRepository.cs index 126694889..6e7c394e3 100644 --- a/src/Ombi.Store/Repository/IRepository.cs +++ b/src/Ombi.Store/Repository/IRepository.cs @@ -14,10 +14,10 @@ namespace Ombi.Store.Repository IQueryable GetAll(); Task FirstOrDefaultAsync(Expression> predicate); Task AddRange(IEnumerable content); + Task Add(T content); Task DeleteRange(IEnumerable req); Task Delete(T request); Task SaveChangesAsync(); - Task Add(T content); IIncludableQueryable Include( IQueryable source, Expression> navigationPropertyPath) diff --git a/src/Ombi.Store/Repository/Requests/IMovieRequestRepository.cs b/src/Ombi.Store/Repository/Requests/IMovieRequestRepository.cs index 64f95fd71..e25b2b168 100644 --- a/src/Ombi.Store/Repository/Requests/IMovieRequestRepository.cs +++ b/src/Ombi.Store/Repository/Requests/IMovieRequestRepository.cs @@ -6,7 +6,6 @@ namespace Ombi.Store.Repository.Requests { public interface IMovieRequestRepository : IRepository { - Task Add(MovieRequests request); Task GetRequestAsync(int theMovieDbId); MovieRequests GetRequest(int theMovieDbId); Task Update(MovieRequests request); diff --git a/src/Ombi.Store/Repository/SettingsJsonRepository.cs b/src/Ombi.Store/Repository/SettingsJsonRepository.cs index f6ebfec71..ba195c372 100644 --- a/src/Ombi.Store/Repository/SettingsJsonRepository.cs +++ b/src/Ombi.Store/Repository/SettingsJsonRepository.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using Ombi.Helpers; using Ombi.Store.Context; using Ombi.Store.Entities; @@ -11,14 +12,14 @@ namespace Ombi.Store.Repository { public class SettingsJsonRepository : ISettingsRepository { - public SettingsJsonRepository(IOmbiContext ctx, IMemoryCache mem) + public SettingsJsonRepository(IOmbiContext ctx, ICacheService mem) { Db = ctx; _cache = mem; } private IOmbiContext Db { get; } - private readonly IMemoryCache _cache; + private readonly ICacheService _cache; public GlobalSettings Insert(GlobalSettings entity) { diff --git a/src/Ombi/ClientApp/app/app.component.html b/src/Ombi/ClientApp/app/app.component.html index b01904104..c6bbf1cae 100644 --- a/src/Ombi/ClientApp/app/app.component.html +++ b/src/Ombi/ClientApp/app/app.component.html @@ -34,6 +34,12 @@ {{ 'NavigationBar.Requests' | translate }} +