diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91ef9d69d..5f39765e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,41 @@
### **New Features**
+- Finished adding subscriptions for TV Shows. [Jamie Rees]
+
+- Added the test button for mobile notifications. [Jamie Rees]
+
+- Added classes to donation html elements. [Anojh]
+
+- Enhanced newsletter styling to support more mail clients. [Anojh]
+
+- Improved the way we sync the plex content and then get the metadata. #2243. [Jamie Rees]
+
+### **Fixes**
+
+- Fixed #2257. [Jamie Rees]
+
+- Fixed the issue when enabling the Hide Request Users included system users e.g. API key user #2232. [Jamie Rees]
+
+- Fix #2167. [Anojh]
+
+- Fix #2228. [Anojh]
+
+- Fix #2246. [Anojh]
+
+- Fix #2234. [Anojh]
+
+- Fixed that sometimes there would be a hidden error on the login page. [Jamie Rees]
+
+
+## v3.0.3304 (2018-05-09)
+
+### **New Features**
+
- Updated to prevent security vulnerability as noted here: https://github.com/aspnet/Announcements/issues/300. [Jamie Rees]
+- Update README.md. [Jamie]
+
### **Fixes**
- [LC] - Added classes to root/quality override divs. [Anojh]
diff --git a/README.md b/README.md
index 1c2dc9559..2049af360 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,9 @@ ____
[![Patreon](https://img.shields.io/badge/patreon-donate-yellow.svg)](https://patreon.com/tidusjar/Ombi)
[![Paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://paypal.me/PlexRequestsNet)
+___
+
+
___
We also now have merch up on Teespring!
diff --git a/src/Ombi.Core/Engine/BaseMediaEngine.cs b/src/Ombi.Core/Engine/BaseMediaEngine.cs
index 552b2ac38..2eab74b75 100644
--- a/src/Ombi.Core/Engine/BaseMediaEngine.cs
+++ b/src/Ombi.Core/Engine/BaseMediaEngine.cs
@@ -9,13 +9,12 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests;
-using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests;
-using Ombi.Store.Entities;
-using Microsoft.AspNetCore.Identity;
using Ombi.Core.Authentication;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
+using Ombi.Store.Repository;
namespace Ombi.Core.Engine
{
@@ -26,11 +25,12 @@ namespace Ombi.Core.Engine
private Dictionary _dbTv;
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
- IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService ombiSettings) : base(identity, um, rules)
+ IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService ombiSettings, IRepository sub) : base(identity, um, rules)
{
RequestService = requestService;
Cache = cache;
OmbiSettings = ombiSettings;
+ _subscriptionRepository = sub;
}
protected IRequestServiceMain RequestService { get; }
@@ -38,6 +38,7 @@ namespace Ombi.Core.Engine
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
protected readonly ICacheService Cache;
protected readonly ISettingsService OmbiSettings;
+ protected readonly IRepository _subscriptionRepository;
protected async Task> GetMovieRequests()
{
@@ -78,7 +79,7 @@ namespace Ombi.Core.Engine
var pendingTv = 0;
var approvedTv = 0;
- var availableTv = 0;
+ var availableTv = 0;
foreach (var tv in tvQuery)
{
foreach (var child in tv.ChildRequests)
@@ -108,21 +109,51 @@ namespace Ombi.Core.Engine
protected async Task HideFromOtherUsers()
{
- if (await IsInRole(OmbiRoles.Admin) || await IsInRole(OmbiRoles.PowerUser))
+ var user = await GetUser();
+ if (await IsInRole(OmbiRoles.Admin) || await IsInRole(OmbiRoles.PowerUser) || user.IsSystemUser)
{
- return new HideResult();
+ return new HideResult
+ {
+ UserId = user.Id
+ };
}
var settings = await Cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await OmbiSettings.GetSettingsAsync());
var result = new HideResult
{
- Hide = settings.HideRequestsUsers
+ Hide = settings.HideRequestsUsers,
+ UserId = user.Id
+ };
+ return result;
+ }
+
+ public async Task SubscribeToRequest(int requestId, RequestType type)
+ {
+ var user = await GetUser();
+ var existingSub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(x =>
+ x.UserId.Equals(user.Id) && x.RequestId == requestId && x.RequestType == type);
+ if (existingSub != null)
+ {
+ return;
+ }
+ var sub = new RequestSubscription
+ {
+ UserId = user.Id,
+ RequestId = requestId,
+ RequestType = type
};
- if (settings.HideRequestsUsers)
+
+ await _subscriptionRepository.Add(sub);
+ }
+
+ public async Task UnSubscribeRequest(int requestId, RequestType type)
+ {
+ var user = await GetUser();
+ var existingSub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(x =>
+ x.UserId.Equals(user.Id) && x.RequestId == requestId && x.RequestType == type);
+ if (existingSub != null)
{
- var user = await GetUser();
- result.UserId = user.Id;
+ await _subscriptionRepository.Delete(existingSub);
}
- return result;
}
public class HideResult
diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs
index 08ec9b594..c1ba76a7c 100644
--- a/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs
+++ b/src/Ombi.Core/Engine/Interfaces/IMovieRequestEngine.cs
@@ -18,6 +18,7 @@ namespace Ombi.Core.Engine.Interfaces
Task ApproveMovieById(int requestId);
Task DenyMovieById(int modelId);
Task> Filter(FilterViewModel vm);
+
}
}
\ No newline at end of file
diff --git a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs
index 5dbf6e449..553ad79dd 100644
--- a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs
+++ b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Core.Models.Requests;
+using Ombi.Store.Entities;
namespace Ombi.Core.Engine.Interfaces
{
@@ -18,5 +19,7 @@ namespace Ombi.Core.Engine.Interfaces
Task MarkUnavailable(int modelId);
Task MarkAvailable(int modelId);
Task GetTotal();
+ Task UnSubscribeRequest(int requestId, RequestType type);
+ Task SubscribeToRequest(int requestId, RequestType type);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs
index 3d88b7230..460752bb1 100644
--- a/src/Ombi.Core/Engine/MovieRequestEngine.cs
+++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs
@@ -25,7 +25,8 @@ namespace Ombi.Core.Engine
{
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger log,
- OmbiUserManager manager, IRepository rl, ICacheService cache, ISettingsService ombiSettings) : base(user, requestService, r, manager, cache, ombiSettings)
+ OmbiUserManager manager, IRepository rl, ICacheService cache, ISettingsService ombiSettings, IRepository sub)
+ : base(user, requestService, r, manager, cache, ombiSettings, sub)
{
MovieApi = movieApi;
NotificationHelper = helper;
@@ -137,9 +138,10 @@ namespace Ombi.Core.Engine
{
allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
}
- allRequests.ForEach(x =>
+ allRequests.ForEach(async x =>
{
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
+ await CheckForSubscription(shouldHide, x);
});
return allRequests;
}
@@ -173,9 +175,30 @@ namespace Ombi.Core.Engine
{
allRequests = await MovieRepository.GetWithUser().ToListAsync();
}
+
+ allRequests.ForEach(async x =>
+ {
+ x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
+ await CheckForSubscription(shouldHide, x);
+ });
return allRequests;
}
+ private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x)
+ {
+ if (shouldHide.UserId == x.RequestedUserId)
+ {
+ x.ShowSubscribe = false;
+ }
+ else
+ {
+ x.ShowSubscribe = true;
+ var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
+ s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie);
+ x.Subscribed = sub != null;
+ }
+ }
+
///
/// Searches the movie request.
///
@@ -194,9 +217,10 @@ namespace Ombi.Core.Engine
allRequests = await MovieRepository.GetWithUser().ToListAsync();
}
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
- results.ForEach(x =>
+ results.ForEach(async x =>
{
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
+ await CheckForSubscription(shouldHide, x);
});
return results;
}
diff --git a/src/Ombi.Core/Engine/MovieSearchEngine.cs b/src/Ombi.Core/Engine/MovieSearchEngine.cs
index 448ff9235..915eefe02 100644
--- a/src/Ombi.Core/Engine/MovieSearchEngine.cs
+++ b/src/Ombi.Core/Engine/MovieSearchEngine.cs
@@ -15,14 +15,16 @@ using Ombi.Core.Authentication;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
+using Ombi.Store.Repository;
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, ICacheService mem, ISettingsService s)
- : base(identity, service, r, um, mem, s)
+ ILogger logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService s, IRepository sub)
+ : base(identity, service, r, um, mem, s, sub)
{
MovieApi = movApi;
Mapper = mapper;
diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs
index 2ce4da292..d74b45e5e 100644
--- a/src/Ombi.Core/Engine/TvRequestEngine.cs
+++ b/src/Ombi.Core/Engine/TvRequestEngine.cs
@@ -29,7 +29,8 @@ namespace Ombi.Core.Engine
{
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
- ITvSender sender, IAuditRepository audit, IRepository rl, ISettingsService settings, ICacheService cache) : base(user, requestService, rule, manager, cache, settings)
+ ITvSender sender, IAuditRepository audit, IRepository rl, ISettingsService settings, ICacheService cache,
+ IRepository sub) : base(user, requestService, rule, manager, cache, settings, sub)
{
TvApi = tvApi;
MovieDbApi = movApi;
@@ -156,6 +157,8 @@ namespace Ombi.Core.Engine
.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
}
+ allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
+
return allRequests;
}
@@ -181,25 +184,28 @@ namespace Ombi.Core.Engine
.ThenInclude(x => x.Episodes)
.Skip(position).Take(count).ToListAsync();
}
+
+ allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
return ParseIntoTreeNode(allRequests);
}
public async Task> GetRequests()
{
var shouldHide = await HideFromOtherUsers();
- IQueryable allRequests;
+ List allRequests;
if (shouldHide.Hide)
{
- allRequests = TvRepository.Get(shouldHide.UserId);
+ allRequests = await TvRepository.Get(shouldHide.UserId).ToListAsync();
FilterChildren(allRequests, shouldHide);
}
else
{
- allRequests = TvRepository.Get();
+ allRequests = await TvRepository.Get().ToListAsync();
}
- return await allRequests.ToListAsync();
+ allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
+ return allRequests;
}
private static void FilterChildren(IEnumerable allRequests, HideResult shouldHide)
@@ -232,6 +238,8 @@ namespace Ombi.Core.Engine
allRequests = await TvRepository.GetChild().Include(x => x.SeasonRequests).Where(x => x.ParentRequestId == tvId).ToListAsync();
}
+ allRequests.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
+
return allRequests;
}
@@ -248,6 +256,8 @@ namespace Ombi.Core.Engine
allRequests = TvRepository.Get();
}
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
+
+ results.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
return results;
}
@@ -264,6 +274,7 @@ namespace Ombi.Core.Engine
allRequests = TvRepository.Get();
}
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
+ results.ForEach(async r => { await CheckForSubscription(shouldHide, r); });
return ParseIntoTreeNode(results);
}
@@ -445,6 +456,29 @@ namespace Ombi.Core.Engine
}
}
+ private async Task CheckForSubscription(HideResult shouldHide, TvRequests x)
+ {
+ foreach (var tv in x.ChildRequests)
+ {
+ await CheckForSubscription(shouldHide, tv);
+ }
+ }
+
+ private async Task CheckForSubscription(HideResult shouldHide, ChildRequests x)
+ {
+ if (shouldHide.UserId == x.RequestedUserId)
+ {
+ x.ShowSubscribe = false;
+ }
+ else
+ {
+ x.ShowSubscribe = true;
+ var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
+ s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.TvShow);
+ x.Subscribed = sub != null;
+ }
+ }
+
private async Task AddExistingRequest(ChildRequests newRequest, TvRequests existingRequest)
{
// Add the child
diff --git a/src/Ombi.Core/Engine/TvSearchEngine.cs b/src/Ombi.Core/Engine/TvSearchEngine.cs
index 1664ecfa7..bc5a2e984 100644
--- a/src/Ombi.Core/Engine/TvSearchEngine.cs
+++ b/src/Ombi.Core/Engine/TvSearchEngine.cs
@@ -20,6 +20,7 @@ using Microsoft.Extensions.Caching.Memory;
using Ombi.Core.Authentication;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models;
+using Ombi.Store.Entities;
namespace Ombi.Core.Engine
{
@@ -27,8 +28,8 @@ 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,
- ICacheService memCache, ISettingsService s)
- : base(identity, service, r, um, memCache, s)
+ ICacheService memCache, ISettingsService s, IRepository sub)
+ : base(identity, service, r, um, memCache, s, sub)
{
TvMazeApi = tvMaze;
Mapper = mapper;
diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs
index 68f4b7218..dcae39cb0 100644
--- a/src/Ombi.DependencyInjection/IocExtensions.cs
+++ b/src/Ombi.DependencyInjection/IocExtensions.cs
@@ -152,6 +152,7 @@ namespace Ombi.DependencyInjection
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
services.AddTransient();
}
diff --git a/src/Ombi.Notifications/Agents/DiscordNotification.cs b/src/Ombi.Notifications/Agents/DiscordNotification.cs
index 0a5d5dabc..66280ef70 100644
--- a/src/Ombi.Notifications/Agents/DiscordNotification.cs
+++ b/src/Ombi.Notifications/Agents/DiscordNotification.cs
@@ -20,8 +20,8 @@ namespace Ombi.Notifications.Agents
{
public DiscordNotification(IDiscordApi api, ISettingsService sn,
ILogger log, INotificationTemplatesRepository r,
- IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s)
- : base(sn, r, m, t,s,log)
+ IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository sub)
+ : base(sn, r, m, t,s,log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Agents/EmailNotification.cs b/src/Ombi.Notifications/Agents/EmailNotification.cs
index d8f005e2b..53046ade0 100644
--- a/src/Ombi.Notifications/Agents/EmailNotification.cs
+++ b/src/Ombi.Notifications/Agents/EmailNotification.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using Microsoft.AspNetCore.Identity;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using MimeKit;
using Ombi.Core.Settings;
@@ -21,7 +22,7 @@ namespace Ombi.Notifications.Agents
public class EmailNotification : BaseNotification, IEmailNotification
{
public EmailNotification(ISettingsService settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService c,
- ILogger log, UserManager um) : base(settings, r, m, t, c, log)
+ ILogger log, UserManager um, IRepository sub) : base(settings, r, m, t, c, log, sub)
{
EmailProvider = prov;
Logger = log;
@@ -52,7 +53,7 @@ namespace Ombi.Notifications.Agents
return true;
}
-
+
private async Task LoadTemplate(NotificationType type, NotificationOptions model, EmailNotificationSettings settings)
{
var parsed = await LoadTemplate(NotificationAgent.Email, type, model);
@@ -62,8 +63,8 @@ namespace Ombi.Notifications.Agents
return null;
}
var email = new EmailBasicTemplate();
- var html = email.LoadTemplate(parsed.Subject, parsed.Message,parsed.Image, Customization.Logo);
-
+ var html = email.LoadTemplate(parsed.Subject, parsed.Message, parsed.Image, Customization.Logo);
+
var message = new NotificationMessage
{
@@ -154,7 +155,7 @@ namespace Ombi.Notifications.Agents
{
message.To = model.Recipient;
}
-
+
await Send(message, settings);
}
@@ -176,7 +177,7 @@ namespace Ombi.Notifications.Agents
// Issues resolved should be sent to the user
message.To = model.Recipient;
-
+
await Send(message, settings);
}
@@ -227,10 +228,12 @@ namespace Ombi.Notifications.Agents
var plaintext = await LoadPlainTextMessage(NotificationType.RequestDeclined, model, settings);
message.Other.Add("PlainTextBody", plaintext);
+ await SendToSubscribers(settings, message);
message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email;
await Send(message, settings);
+
}
protected override async Task RequestApproved(NotificationOptions model, EmailNotificationSettings settings)
@@ -244,12 +247,32 @@ namespace Ombi.Notifications.Agents
var plaintext = await LoadPlainTextMessage(NotificationType.RequestApproved, model, settings);
message.Other.Add("PlainTextBody", plaintext);
+ await SendToSubscribers(settings, message);
+
message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email;
await Send(message, settings);
}
+ private async Task SendToSubscribers(EmailNotificationSettings settings, NotificationMessage message)
+ {
+ if (await SubsribedUsers.AnyAsync())
+ {
+ foreach (var user in SubsribedUsers)
+ {
+ if (user.Email.IsNullOrEmpty())
+ {
+ continue;
+ }
+
+ message.To = user.Email;
+
+ await Send(message, settings);
+ }
+ }
+ }
+
protected override async Task AvailableRequest(NotificationOptions model, EmailNotificationSettings settings)
{
var message = await LoadTemplate(NotificationType.RequestAvailable, model, settings);
@@ -260,7 +283,7 @@ namespace Ombi.Notifications.Agents
var plaintext = await LoadPlainTextMessage(NotificationType.RequestAvailable, model, settings);
message.Other.Add("PlainTextBody", plaintext);
-
+ await SendToSubscribers(settings, message);
message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email;
diff --git a/src/Ombi.Notifications/Agents/Interfaces/IMobileNotification.cs b/src/Ombi.Notifications/Agents/Interfaces/IMobileNotification.cs
new file mode 100644
index 000000000..1daf7e46a
--- /dev/null
+++ b/src/Ombi.Notifications/Agents/Interfaces/IMobileNotification.cs
@@ -0,0 +1,6 @@
+namespace Ombi.Notifications.Agents
+{
+ public interface IMobileNotification : INotification
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Notifications/Agents/MattermostNotification.cs b/src/Ombi.Notifications/Agents/MattermostNotification.cs
index f07d62b72..8590bfaae 100644
--- a/src/Ombi.Notifications/Agents/MattermostNotification.cs
+++ b/src/Ombi.Notifications/Agents/MattermostNotification.cs
@@ -21,7 +21,7 @@ namespace Ombi.Notifications.Agents
public class MattermostNotification : BaseNotification, IMattermostNotification
{
public MattermostNotification(IMattermostApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
- ISettingsService s) : base(sn, r, m, t,s,log)
+ ISettingsService s, IRepository sub) : base(sn, r, m, t,s,log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Agents/MobileNotification.cs b/src/Ombi.Notifications/Agents/MobileNotification.cs
index 575801bd2..35619ad1f 100644
--- a/src/Ombi.Notifications/Agents/MobileNotification.cs
+++ b/src/Ombi.Notifications/Agents/MobileNotification.cs
@@ -18,11 +18,11 @@ using Ombi.Store.Repository.Requests;
namespace Ombi.Notifications.Agents
{
- public class MobileNotification : BaseNotification
+ public class MobileNotification : BaseNotification, IMobileNotification
{
public MobileNotification(IOneSignalApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r,
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService s, IRepository notification,
- UserManager um) : base(sn, r, m, t, s,log)
+ UserManager um, IRepository sub) : base(sn, r, m, t, s,log, sub)
{
_api = api;
_logger = log;
@@ -167,6 +167,7 @@ namespace Ombi.Notifications.Agents
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestDeclined);
+ await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings);
}
@@ -185,6 +186,8 @@ namespace Ombi.Notifications.Agents
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestApproved);
+
+ await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings);
}
@@ -202,6 +205,8 @@ namespace Ombi.Notifications.Agents
};
// Send to user
var playerIds = GetUsers(model, NotificationType.RequestAvailable);
+
+ await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings);
}
protected override Task Send(NotificationMessage model, MobileNotificationSettings settings)
@@ -227,7 +232,13 @@ namespace Ombi.Notifications.Agents
Message = message,
};
// Send to user
- var playerIds = await GetAdmins(NotificationType.RequestAvailable);
+ var user = await _userManager.Users.Include(x => x.NotificationUserIds).FirstOrDefaultAsync(x => x.Id.Equals(model.UserId));
+ if (user == null)
+ {
+ return;
+ }
+
+ var playerIds = user.NotificationUserIds.Select(x => x.PlayerId).ToList();
await Send(playerIds, notification, settings);
}
@@ -269,6 +280,20 @@ namespace Ombi.Notifications.Agents
return playerIds;
}
+ private async Task AddSubscribedUsers(List playerIds)
+ {
+ if (await SubsribedUsers.AnyAsync())
+ {
+ foreach (var user in SubsribedUsers.Include(x => x.NotificationUserIds))
+ {
+ var notificationId = user.NotificationUserIds;
+ if (notificationId.Any())
+ {
+ playerIds.AddRange(notificationId.Select(x => x.PlayerId));
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Ombi.Notifications/Agents/PushbulletNotification.cs b/src/Ombi.Notifications/Agents/PushbulletNotification.cs
index 21a384db6..24aa8cd22 100644
--- a/src/Ombi.Notifications/Agents/PushbulletNotification.cs
+++ b/src/Ombi.Notifications/Agents/PushbulletNotification.cs
@@ -17,7 +17,7 @@ namespace Ombi.Notifications.Agents
public class PushbulletNotification : BaseNotification, IPushbulletNotification
{
public PushbulletNotification(IPushbulletApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
- ISettingsService s) : base(sn, r, m, t,s,log)
+ ISettingsService s, IRepository sub) : base(sn, r, m, t,s,log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Agents/PushoverNotification.cs b/src/Ombi.Notifications/Agents/PushoverNotification.cs
index 505adc44e..5b82eb8a3 100644
--- a/src/Ombi.Notifications/Agents/PushoverNotification.cs
+++ b/src/Ombi.Notifications/Agents/PushoverNotification.cs
@@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
public class PushoverNotification : BaseNotification, IPushoverNotification
{
public PushoverNotification(IPushoverApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
- ISettingsService s) : base(sn, r, m, t, s, log)
+ ISettingsService s, IRepository sub) : base(sn, r, m, t, s, log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Agents/SlackNotification.cs b/src/Ombi.Notifications/Agents/SlackNotification.cs
index d723c065a..894758591 100644
--- a/src/Ombi.Notifications/Agents/SlackNotification.cs
+++ b/src/Ombi.Notifications/Agents/SlackNotification.cs
@@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
public class SlackNotification : BaseNotification, ISlackNotification
{
public SlackNotification(ISlackApi api, ISettingsService sn, ILogger log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
- ISettingsService s) : base(sn, r, m, t, s, log)
+ ISettingsService s, IRepository sub) : base(sn, r, m, t, s, log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Agents/TelegramNotification.cs b/src/Ombi.Notifications/Agents/TelegramNotification.cs
index 921fd3ad2..827b0b590 100644
--- a/src/Ombi.Notifications/Agents/TelegramNotification.cs
+++ b/src/Ombi.Notifications/Agents/TelegramNotification.cs
@@ -18,7 +18,8 @@ namespace Ombi.Notifications.Agents
{
public TelegramNotification(ITelegramApi api, ISettingsService sn, ILogger log,
INotificationTemplatesRepository r, IMovieRequestRepository m,
- ITvRequestRepository t, ISettingsService s) : base(sn, r, m, t,s,log)
+ ITvRequestRepository t, ISettingsService s
+ , IRepository sub) : base(sn, r, m, t,s,log, sub)
{
Api = api;
Logger = log;
diff --git a/src/Ombi.Notifications/Interfaces/BaseNotification.cs b/src/Ombi.Notifications/Interfaces/BaseNotification.cs
index f21d3fb12..507b8059b 100644
--- a/src/Ombi.Notifications/Interfaces/BaseNotification.cs
+++ b/src/Ombi.Notifications/Interfaces/BaseNotification.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@@ -17,7 +19,7 @@ namespace Ombi.Notifications.Interfaces
public abstract class BaseNotification : INotification where T : Settings.Settings.Models.Settings, new()
{
protected BaseNotification(ISettingsService settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv,
- ISettingsService customization, ILogger> log)
+ ISettingsService customization, ILogger> log, IRepository sub)
{
Settings = settings;
TemplateRepository = templateRepo;
@@ -26,21 +28,24 @@ namespace Ombi.Notifications.Interfaces
CustomizationSettings = customization;
Settings.ClearCache();
CustomizationSettings.ClearCache();
+ RequestSubscription = sub;
_log = log;
}
-
+
protected ISettingsService Settings { get; }
protected INotificationTemplatesRepository TemplateRepository { get; }
protected IMovieRequestRepository MovieRepository { get; }
protected ITvRequestRepository TvRepository { get; }
protected CustomizationSettings Customization { get; set; }
+ protected IRepository RequestSubscription { get; set; }
private ISettingsService CustomizationSettings { get; }
private readonly ILogger> _log;
protected ChildRequests TvRequest { get; set; }
protected MovieRequests MovieRequest { get; set; }
-
+ protected IQueryable SubsribedUsers { get; private set; }
+
public abstract string NotificationName { get; }
public async Task NotifyAsync(NotificationOptions model)
@@ -54,20 +59,21 @@ namespace Ombi.Notifications.Interfaces
{
Settings.ClearCache();
if (settings == null) await NotifyAsync(model);
-
+
var notificationSettings = (T)settings;
-
+
if (!ValidateConfiguration(notificationSettings))
{
return;
}
-
+
// 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);
+ SubsribedUsers = GetSubscriptions(model.RequestId, model.RequestType);
}
Customization = await CustomizationSettings.GetSettingsAsync();
@@ -126,7 +132,7 @@ namespace Ombi.Notifications.Interfaces
}
else
{
- TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
+ TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
}
}
@@ -152,13 +158,19 @@ namespace Ombi.Notifications.Interfaces
}
if (!template.Enabled)
{
- return new NotificationMessageContent {Disabled = true};
+ return new NotificationMessageContent { Disabled = true };
}
var parsed = Parse(model, template);
return parsed;
}
+ protected IQueryable GetSubscriptions(int requestId, RequestType type)
+ {
+ var subs = RequestSubscription.GetAll().Include(x => x.User).Where(x => x.RequestId == requestId && type == x.RequestType);
+ return subs.Select(x => x.User);
+ }
+
private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template)
{
var resolver = new NotificationMessageResolver();
@@ -166,7 +178,7 @@ namespace Ombi.Notifications.Interfaces
if (model.RequestType == RequestType.Movie)
{
_log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization);
-
+
curlys.Setup(model, MovieRequest, Customization);
}
else
diff --git a/src/Ombi.Schedule/Jobs/Ombi/IRefreshMetadata.cs b/src/Ombi.Schedule/Jobs/Ombi/IRefreshMetadata.cs
index a08db74d0..ed13280b0 100644
--- a/src/Ombi.Schedule/Jobs/Ombi/IRefreshMetadata.cs
+++ b/src/Ombi.Schedule/Jobs/Ombi/IRefreshMetadata.cs
@@ -1,9 +1,11 @@
-using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Threading.Tasks;
namespace Ombi.Schedule.Jobs.Ombi
{
public interface IRefreshMetadata : IBaseJob
{
Task Start();
+ Task ProcessPlexServerContent(IEnumerable contentIds);
}
}
\ No newline at end of file
diff --git a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs
index 9b7726a15..4eae94666 100644
--- a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs
+++ b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -17,7 +18,7 @@ namespace Ombi.Schedule.Jobs.Ombi
{
public RefreshMetadata(IPlexContentRepository plexRepo, IEmbyContentRepository embyRepo,
ILogger log, ITvMazeApi tvApi, ISettingsService plexSettings,
- IMovieDbApi movieApi)
+ IMovieDbApi movieApi, ISettingsService embySettings)
{
_plexRepo = plexRepo;
_embyRepo = embyRepo;
@@ -25,6 +26,7 @@ namespace Ombi.Schedule.Jobs.Ombi
_movieApi = movieApi;
_tvApi = tvApi;
_plexSettings = plexSettings;
+ _embySettings = embySettings;
}
private readonly IPlexContentRepository _plexRepo;
@@ -33,6 +35,7 @@ namespace Ombi.Schedule.Jobs.Ombi
private readonly IMovieDbApi _movieApi;
private readonly ITvMazeApi _tvApi;
private readonly ISettingsService _plexSettings;
+ private readonly ISettingsService _embySettings;
public async Task Start()
{
@@ -43,6 +46,11 @@ namespace Ombi.Schedule.Jobs.Ombi
if (settings.Enable)
{
await StartPlex();
+ }
+
+ var embySettings = await _embySettings.GetSettingsAsync();
+ if (embySettings.Enable)
+ {
await StartEmby();
}
}
@@ -53,12 +61,45 @@ namespace Ombi.Schedule.Jobs.Ombi
}
}
+ public async Task ProcessPlexServerContent(IEnumerable contentIds)
+ {
+ _log.LogInformation("Starting the Metadata refresh from RecentlyAddedSync");
+ try
+ {
+ var settings = await _plexSettings.GetSettingsAsync();
+ if (settings.Enable)
+ {
+ await StartPlexWithKnownContent(contentIds);
+ }
+ }
+ catch (Exception e)
+ {
+ _log.LogError(e, "Exception when refreshing the Plex Metadata");
+ throw;
+ }
+ }
+
+ private async Task StartPlexWithKnownContent(IEnumerable contentids)
+ {
+ var everything = _plexRepo.GetAll().Where(x => contentids.Contains(x.Id));
+ var allMovies = everything.Where(x => x.Type == PlexMediaTypeEntity.Movie);
+ await StartPlexMovies(allMovies);
+
+ // Now Tv
+ var allTv = everything.Where(x => x.Type == PlexMediaTypeEntity.Show);
+ await StartPlexTv(allTv);
+ }
+
private async Task StartPlex()
{
- await StartPlexMovies();
+ var allMovies = _plexRepo.GetAll().Where(x =>
+ x.Type == PlexMediaTypeEntity.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
+ await StartPlexMovies(allMovies);
// Now Tv
- await StartPlexTv();
+ var allTv = _plexRepo.GetAll().Where(x =>
+ x.Type == PlexMediaTypeEntity.Show && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue()));
+ await StartPlexTv(allTv);
}
private async Task StartEmby()
@@ -67,10 +108,8 @@ namespace Ombi.Schedule.Jobs.Ombi
await StartEmbyTv();
}
- private async Task StartPlexTv()
+ private async Task StartPlexTv(IQueryable allTv)
{
- var allTv = _plexRepo.GetAll().Where(x =>
- x.Type == PlexMediaTypeEntity.Show && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue() || !x.TvDbId.HasValue()));
var tvCount = 0;
foreach (var show in allTv)
{
@@ -147,10 +186,8 @@ namespace Ombi.Schedule.Jobs.Ombi
await _embyRepo.SaveChangesAsync();
}
- private async Task StartPlexMovies()
+ private async Task StartPlexMovies(IQueryable allMovies)
{
- var allMovies = _plexRepo.GetAll().Where(x =>
- x.Type == PlexMediaTypeEntity.Movie && (!x.TheMovieDbId.HasValue() || !x.ImdbId.HasValue()));
int movieCount = 0;
foreach (var movie in allMovies)
{
diff --git a/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexEpisodeSync.cs
index 7d97381be..ede393790 100644
--- a/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexEpisodeSync.cs
+++ b/src/Ombi.Schedule/Jobs/Plex/Interfaces/IPlexEpisodeSync.cs
@@ -1,10 +1,14 @@
using System;
+using System.Linq;
using System.Threading.Tasks;
+using Ombi.Api.Plex.Models;
+using Ombi.Store.Entities;
namespace Ombi.Schedule.Jobs.Plex.Interfaces
{
public interface IPlexEpisodeSync : IBaseJob
{
Task Start();
+ Task ProcessEpsiodes(Metadata[] episodes, IQueryable currentEpisodes);
}
}
\ 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 334b51e4b..95cd3ba38 100644
--- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs
+++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs
@@ -77,46 +77,86 @@ namespace Ombi.Schedule.Jobs.Plex
Logger.LogError("Plex Settings are not valid");
return;
}
-
+ var processedContent = new HashSet();
Logger.LogInformation("Starting Plex Content Cacher");
try
{
- await StartTheCache(plexSettings, recentlyAddedSearch);
+ if (recentlyAddedSearch)
+ {
+ var result = await StartTheCache(plexSettings, true);
+ foreach (var r in result)
+ {
+ processedContent.Add(r);
+ }
+ }
+ else
+ {
+ await StartTheCache(plexSettings, false);
+ }
}
catch (Exception e)
{
Logger.LogWarning(LoggingEvents.PlexContentCacher, e, "Exception thrown when attempting to cache the Plex Content");
}
- Logger.LogInformation("Starting EP Cacher");
- BackgroundJob.Enqueue(() => EpisodeSync.Start());
- BackgroundJob.Enqueue(() => Metadata.Start());
+ if (!recentlyAddedSearch)
+ {
+ Logger.LogInformation("Starting EP Cacher");
+ BackgroundJob.Enqueue(() => EpisodeSync.Start());
+ }
+
+ if (processedContent.Any() && recentlyAddedSearch)
+ {
+ // Just check what we send it
+ BackgroundJob.Enqueue(() => Metadata.ProcessPlexServerContent(processedContent));
+ }
}
- private async Task StartTheCache(PlexSettings plexSettings, bool recentlyAddedSearch)
+ private async Task> StartTheCache(PlexSettings plexSettings, bool recentlyAddedSearch)
{
+ var processedContent = new HashSet();
foreach (var servers in plexSettings.Servers ?? new List())
{
try
{
Logger.LogInformation("Starting to cache the content on server {0}", servers.Name);
- await ProcessServer(servers, recentlyAddedSearch);
+
+ if (recentlyAddedSearch)
+ {
+ // If it's recently added search then we want the results to pass to the metadata job
+ // This way the metadata job is smaller in size to process, it only need to look at newly added shit
+ var result = await ProcessServer(servers, true);
+ foreach (var plexServerContent in result)
+ {
+ processedContent.Add(plexServerContent);
+ }
+ }
+ else
+ {
+ await ProcessServer(servers, false);
+ }
}
catch (Exception e)
{
Logger.LogWarning(LoggingEvents.PlexContentCacher, e, "Exception thrown when attempting to cache the Plex Content in server {0}", servers.Name);
}
}
+
+ return processedContent;
}
- private async Task ProcessServer(PlexServers servers, bool recentlyAddedSearch)
+ private async Task> ProcessServer(PlexServers servers, bool recentlyAddedSearch)
{
+ var processedContent = new HashSet();
Logger.LogInformation("Getting all content from server {0}", servers.Name);
var allContent = await GetAllContent(servers, recentlyAddedSearch);
Logger.LogInformation("We found {0} items", allContent.Count);
// Let's now process this.
var contentToAdd = new HashSet();
+
+ var allEps = Repo.GetAllEpisodes();
+
foreach (var content in allContent)
{
if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.CurrentCultureIgnoreCase))
@@ -133,8 +173,10 @@ namespace Ombi.Schedule.Jobs.Plex
continue;
}
- await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch);
+ await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
}
+
+ await EpisodeSync.ProcessEpsiodes(content.Metadata, allEps);
}
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
{
@@ -142,7 +184,7 @@ namespace Ombi.Schedule.Jobs.Plex
Logger.LogInformation("Processing TV Shows");
foreach (var show in content.Metadata ?? new Metadata[] { })
{
- await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch);
+ await ProcessTvShow(servers, show, contentToAdd, recentlyAddedSearch, processedContent);
}
}
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
@@ -212,6 +254,10 @@ namespace Ombi.Schedule.Jobs.Plex
if (contentToAdd.Count > 500)
{
await Repo.AddRange(contentToAdd);
+ foreach (var c in contentToAdd)
+ {
+ processedContent.Add(c.Id);
+ }
contentToAdd.Clear();
}
}
@@ -219,6 +265,10 @@ namespace Ombi.Schedule.Jobs.Plex
if (contentToAdd.Count > 500)
{
await Repo.AddRange(contentToAdd);
+ foreach (var c in contentToAdd)
+ {
+ processedContent.Add(c.Id);
+ }
contentToAdd.Clear();
}
}
@@ -226,10 +276,16 @@ namespace Ombi.Schedule.Jobs.Plex
if (contentToAdd.Any())
{
await Repo.AddRange(contentToAdd);
+ foreach (var c in contentToAdd)
+ {
+ processedContent.Add(c.Id);
+ }
}
+
+ return processedContent;
}
- private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet contentToAdd, bool recentlyAdded)
+ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet contentToAdd, bool recentlyAdded, HashSet contentProcessed)
{
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
show.ratingKey);
@@ -412,8 +468,17 @@ namespace Ombi.Schedule.Jobs.Plex
if (contentToAdd.Count > 500 || recentlyAdded)
{
await Repo.AddRange(contentToAdd);
+ foreach (var plexServerContent in contentToAdd)
+ {
+ contentProcessed.Add(plexServerContent.Id);
+ }
contentToAdd.Clear();
}
+
+ if (contentToAdd.Any())
+ {
+ await Repo.AddRange(contentToAdd);
+ }
}
///
diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs
index 8e8cce411..d98eace4a 100644
--- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs
+++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs
@@ -111,7 +111,7 @@ namespace Ombi.Schedule.Jobs.Plex
// 12.03.2017 - I think we should be able to match them now
//await _repo.ExecuteSql("DELETE FROM PlexEpisode");
- await ProcessEpsiodes(episodes, currentEpisodes);
+ await ProcessEpsiodes(episodes?.MediaContainer?.Metadata ?? new Metadata[] { }, currentEpisodes);
currentPosition += resultCount;
while (currentPosition < episodes.MediaContainer.totalSize)
@@ -119,7 +119,7 @@ namespace Ombi.Schedule.Jobs.Plex
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
resultCount);
- await ProcessEpsiodes(ep, currentEpisodes);
+ await ProcessEpsiodes(ep?.MediaContainer?.Metadata ?? new Metadata[] { }, currentEpisodes);
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {resultCount} more episodes. Total Remaining {episodes.MediaContainer.totalSize - currentPosition}");
currentPosition += resultCount;
}
@@ -129,12 +129,12 @@ namespace Ombi.Schedule.Jobs.Plex
await _repo.SaveChangesAsync();
}
- private async Task ProcessEpsiodes(PlexContainer episodes, IQueryable currentEpisodes)
+ public async Task ProcessEpsiodes(Metadata[] episodes, IQueryable currentEpisodes)
{
var ep = new HashSet();
try
{
- foreach (var episode in episodes?.MediaContainer?.Metadata ?? new Metadata[] { })
+ foreach (var episode in episodes)
{
// I don't think we need to get the metadata, we only need to get the metadata if we need the provider id (TheTvDbid). Why do we need it for episodes?
// We have the parent and grandparent rating keys to link up to the season and series
diff --git a/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs b/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs
index 37e10a620..e645097ef 100644
--- a/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs
+++ b/src/Ombi.Schedule/Processor/ChangeLogProcessor.cs
@@ -90,15 +90,15 @@ namespace Ombi.Schedule.Processor
}
- return TransformUpdate(release);
+ return TransformUpdate(release,!masterBranch);
}
- private UpdateModel TransformUpdate(Release release)
+ private UpdateModel TransformUpdate(Release release, bool develop)
{
var newUpdate = new UpdateModel
{
- UpdateVersionString = release.Version.Substring(1,8),
+ UpdateVersionString = develop ? release.Version : release.Version.Substring(1,8),
UpdateVersion = release.Version == "(unreleased)" ? 0 : int.Parse(release.Version.Substring(1, 5).Replace(".", "")),
UpdateDate = DateTime.Now,
ChangeLogs = new List(),
diff --git a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs
index 2e56f17db..a5afbeba7 100644
--- a/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs
+++ b/src/Ombi.Settings/Settings/Models/JobSettingsHelper.cs
@@ -25,7 +25,7 @@ namespace Ombi.Settings.Settings.Models
}
public static string PlexRecentlyAdded(JobSettings s)
{
- return Get(s.PlexRecentlyAddedSync, Cron.Hourly(0));
+ return Get(s.PlexRecentlyAddedSync, Cron.MinuteInterval(30));
}
public static string CouchPotato(JobSettings s)
{
@@ -50,7 +50,7 @@ namespace Ombi.Settings.Settings.Models
}
public static string RefreshMetadata(JobSettings s)
{
- return Get(s.RefreshMetadata, Cron.DayInterval(2));
+ return Get(s.RefreshMetadata, Cron.DayInterval(3));
}
private static string Get(string settings, string defaultCron)
diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs
index 55d7db563..0c716c7c4 100644
--- a/src/Ombi.Store/Context/IOmbiContext.cs
+++ b/src/Ombi.Store/Context/IOmbiContext.cs
@@ -42,5 +42,6 @@ namespace Ombi.Store.Context
DbSet SickRageEpisodeCache { get; set; }
DbSet RequestLogs { get; set; }
DbSet RecentlyAddedLogs { get; set; }
+ DbSet RequestSubscription { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs
index d1963e765..8fb05f6ae 100644
--- a/src/Ombi.Store/Context/OmbiContext.cs
+++ b/src/Ombi.Store/Context/OmbiContext.cs
@@ -47,6 +47,7 @@ namespace Ombi.Store.Context
public DbSet SonarrEpisodeCache { get; set; }
public DbSet SickRageCache { get; set; }
public DbSet SickRageEpisodeCache { get; set; }
+ public DbSet RequestSubscription { get; set; }
public DbSet ApplicationConfigurations { get; set; }
diff --git a/src/Ombi.Store/Entities/OmbiUser.cs b/src/Ombi.Store/Entities/OmbiUser.cs
index b3e82390a..f67183982 100644
--- a/src/Ombi.Store/Entities/OmbiUser.cs
+++ b/src/Ombi.Store/Entities/OmbiUser.cs
@@ -36,6 +36,8 @@ namespace Ombi.Store.Entities
[NotMapped]
public bool EmailLogin { get; set; }
+
+ [NotMapped] public bool IsSystemUser => UserType == UserType.SystemUser;
[JsonIgnore]
public override string PasswordHash
diff --git a/src/Ombi.Store/Entities/RequestSubscription.cs b/src/Ombi.Store/Entities/RequestSubscription.cs
new file mode 100644
index 000000000..2f6d530c9
--- /dev/null
+++ b/src/Ombi.Store/Entities/RequestSubscription.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace Ombi.Store.Entities
+{
+ [Table("RequestSubscription")]
+ public class RequestSubscription : Entity
+ {
+ public string UserId { get; set; }
+ public int RequestId { get; set; }
+ public RequestType RequestType { get; set; }
+
+ [ForeignKey(nameof(UserId))]
+ public OmbiUser User { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi.Store/Entities/Requests/ChildRequests.cs b/src/Ombi.Store/Entities/Requests/ChildRequests.cs
index 64c0bcc5c..3b5156ce5 100644
--- a/src/Ombi.Store/Entities/Requests/ChildRequests.cs
+++ b/src/Ombi.Store/Entities/Requests/ChildRequests.cs
@@ -13,6 +13,15 @@ namespace Ombi.Store.Entities.Requests
public int? IssueId { get; set; }
public SeriesType SeriesType { get; set; }
+ ///
+ /// This is to see if the user is subscribed in the UI
+ ///
+ [NotMapped]
+ public bool Subscribed { get; set; }
+
+ [NotMapped]
+ public bool ShowSubscribe { get; set; }
+
[ForeignKey(nameof(IssueId))]
public List Issues { get; set; }
diff --git a/src/Ombi.Store/Entities/Requests/MovieRequests.cs b/src/Ombi.Store/Entities/Requests/MovieRequests.cs
index 998c27707..675035140 100644
--- a/src/Ombi.Store/Entities/Requests/MovieRequests.cs
+++ b/src/Ombi.Store/Entities/Requests/MovieRequests.cs
@@ -12,6 +12,11 @@ namespace Ombi.Store.Entities.Requests
[ForeignKey(nameof(IssueId))]
public List Issues { get; set; }
+ [NotMapped]
+ public bool Subscribed { get; set; }
+ [NotMapped]
+ public bool ShowSubscribe { get; set; }
+
public int RootPathOverride { get; set; }
public int QualityOverride { get; set; }
}
diff --git a/src/Ombi.Store/Entities/Requests/TvRequests.cs b/src/Ombi.Store/Entities/Requests/TvRequests.cs
index 7a6abc792..432bc88ab 100644
--- a/src/Ombi.Store/Entities/Requests/TvRequests.cs
+++ b/src/Ombi.Store/Entities/Requests/TvRequests.cs
@@ -16,6 +16,7 @@ namespace Ombi.Store.Entities.Requests
public string Background { get; set; }
public DateTime ReleaseDate { get; set; }
public string Status { get; set; }
+
///
/// This is so we can correctly send the right amount of seasons to Sonarr
///
diff --git a/src/Ombi.Store/Migrations/20180516090124_RequestSubscription.Designer.cs b/src/Ombi.Store/Migrations/20180516090124_RequestSubscription.Designer.cs
new file mode 100644
index 000000000..e83458fef
--- /dev/null
+++ b/src/Ombi.Store/Migrations/20180516090124_RequestSubscription.Designer.cs
@@ -0,0 +1,981 @@
+//
+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("20180516090124_RequestSubscription")]
+ partial class RequestSubscription
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
+
+ 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("ImdbId");
+
+ b.Property("ProviderId");
+
+ b.Property("TheMovieDbId");
+
+ b.Property("Title");
+
+ b.Property("TvDbId");
+
+ b.Property("Type");
+
+ b.Property("Url");
+
+ 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("ImdbId");
+
+ b.Property("ParentId");
+
+ b.Property("ProviderId");
+
+ b.Property("SeasonNumber");
+
+ b.Property("TheMovieDbId");
+
+ b.Property("Title");
+
+ b.Property("TvDbId");
+
+ 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.NotificationUserId", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AddedAt");
+
+ b.Property("PlayerId");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("NotificationUserId");
+ });
+
+ 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("EpisodeRequestLimit");
+
+ b.Property("LastLoggedIn");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("MovieRequestLimit");
+
+ 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("UserAccessToken");
+
+ 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