Added the subscription for movies !wip

This commit is contained in:
Jamie Rees 2018-05-16 11:00:30 +01:00
parent bebf2f2ab8
commit 7a9fc1213f
31 changed files with 1308 additions and 42 deletions

View file

@ -9,13 +9,12 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using Ombi.Store.Entities;
using Microsoft.AspNetCore.Identity;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -26,11 +25,12 @@ namespace Ombi.Core.Engine
private Dictionary<int, TvRequests> _dbTv; private Dictionary<int, TvRequests> _dbTv;
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService, protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings) : base(identity, um, rules) IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub) : base(identity, um, rules)
{ {
RequestService = requestService; RequestService = requestService;
Cache = cache; Cache = cache;
OmbiSettings = ombiSettings; OmbiSettings = ombiSettings;
_subscriptionRepository = sub;
} }
protected IRequestServiceMain RequestService { get; } protected IRequestServiceMain RequestService { get; }
@ -38,6 +38,7 @@ namespace Ombi.Core.Engine
protected ITvRequestRepository TvRepository => RequestService.TvRequestService; protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
protected readonly ICacheService Cache; protected readonly ICacheService Cache;
protected readonly ISettingsService<OmbiSettings> OmbiSettings; protected readonly ISettingsService<OmbiSettings> OmbiSettings;
protected readonly IRepository<RequestSubscription> _subscriptionRepository;
protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests() protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests()
{ {
@ -108,9 +109,13 @@ namespace Ombi.Core.Engine
protected async Task<HideResult> HideFromOtherUsers() protected async Task<HideResult> HideFromOtherUsers()
{ {
var user = await GetUser();
if (await IsInRole(OmbiRoles.Admin) || await IsInRole(OmbiRoles.PowerUser)) if (await IsInRole(OmbiRoles.Admin) || await IsInRole(OmbiRoles.PowerUser))
{ {
return new HideResult(); return new HideResult
{
UserId = user.Id
};
} }
var settings = await Cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await OmbiSettings.GetSettingsAsync()); var settings = await Cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await OmbiSettings.GetSettingsAsync());
var result = new HideResult var result = new HideResult
@ -119,12 +124,41 @@ namespace Ombi.Core.Engine
}; };
if (settings.HideRequestsUsers) if (settings.HideRequestsUsers)
{ {
var user = await GetUser();
result.UserId = user.Id; result.UserId = user.Id;
} }
return result; 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
};
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)
{
await _subscriptionRepository.Delete(existingSub);
}
}
public class HideResult public class HideResult
{ {
public bool Hide { get; set; } public bool Hide { get; set; }

View file

@ -19,5 +19,6 @@ namespace Ombi.Core.Engine.Interfaces
Task<RequestEngineResult> DenyMovieById(int modelId); Task<RequestEngineResult> DenyMovieById(int modelId);
Task<FilterResult<MovieRequests>> Filter(FilterViewModel vm); Task<FilterResult<MovieRequests>> Filter(FilterViewModel vm);
} }
} }

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Store.Entities;
namespace Ombi.Core.Engine.Interfaces namespace Ombi.Core.Engine.Interfaces
{ {
@ -18,5 +19,7 @@ namespace Ombi.Core.Engine.Interfaces
Task<RequestEngineResult> MarkUnavailable(int modelId); Task<RequestEngineResult> MarkUnavailable(int modelId);
Task<RequestEngineResult> MarkAvailable(int modelId); Task<RequestEngineResult> MarkAvailable(int modelId);
Task<int> GetTotal(); Task<int> GetTotal();
Task UnSubscribeRequest(int requestId, RequestType type);
Task SubscribeToRequest(int requestId, RequestType type);
} }
} }

View file

@ -25,7 +25,8 @@ namespace Ombi.Core.Engine
{ {
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log, INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings) : base(user, requestService, r, manager, cache, ombiSettings) OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub)
: base(user, requestService, r, manager, cache, ombiSettings, sub)
{ {
MovieApi = movieApi; MovieApi = movieApi;
NotificationHelper = helper; NotificationHelper = helper;
@ -140,6 +141,7 @@ namespace Ombi.Core.Engine
allRequests.ForEach(x => allRequests.ForEach(x =>
{ {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
CheckForSubscription(shouldHide, x);
}); });
return allRequests; return allRequests;
} }
@ -173,9 +175,22 @@ namespace Ombi.Core.Engine
{ {
allRequests = await MovieRepository.GetWithUser().ToListAsync(); allRequests = await MovieRepository.GetWithUser().ToListAsync();
} }
allRequests.ForEach(x =>
{
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
CheckForSubscription(shouldHide, x);
});
return allRequests; return allRequests;
} }
private void CheckForSubscription(HideResult shouldHide, MovieRequests x)
{
var sub = _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie);
x.Subscribed = sub != null;
}
/// <summary> /// <summary>
/// Searches the movie request. /// Searches the movie request.
/// </summary> /// </summary>
@ -197,6 +212,7 @@ namespace Ombi.Core.Engine
results.ForEach(x => results.ForEach(x =>
{ {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
CheckForSubscription(shouldHide, x);
}); });
return results; return results;
} }

View file

@ -15,14 +15,16 @@ using Ombi.Core.Authentication;
using Ombi.Core.Settings; using Ombi.Core.Settings;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
{ {
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s) ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
: base(identity, service, r, um, mem, s) : base(identity, service, r, um, mem, s, sub)
{ {
MovieApi = movApi; MovieApi = movApi;
Mapper = mapper; Mapper = mapper;

View file

@ -29,7 +29,8 @@ namespace Ombi.Core.Engine
{ {
public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user, public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache) : base(user, requestService, rule, manager, cache, settings) ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache,
IRepository<RequestSubscription> sub) : base(user, requestService, rule, manager, cache, settings, sub)
{ {
TvApi = tvApi; TvApi = tvApi;
MovieDbApi = movApi; MovieDbApi = movApi;

View file

@ -20,6 +20,7 @@ using Microsoft.Extensions.Caching.Memory;
using Ombi.Core.Authentication; using Ombi.Core.Authentication;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Settings.Settings.Models; using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
@ -27,8 +28,8 @@ namespace Ombi.Core.Engine
{ {
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings, public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um, ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um,
ICacheService memCache, ISettingsService<OmbiSettings> s) ICacheService memCache, ISettingsService<OmbiSettings> s, IRepository<RequestSubscription> sub)
: base(identity, service, r, um, memCache, s) : base(identity, service, r, um, memCache, s, sub)
{ {
TvMazeApi = tvMaze; TvMazeApi = tvMaze;
Mapper = mapper; Mapper = mapper;

View file

@ -20,8 +20,8 @@ namespace Ombi.Notifications.Agents
{ {
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn, public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn,
ILogger<DiscordNotification> log, INotificationTemplatesRepository r, ILogger<DiscordNotification> log, INotificationTemplatesRepository r,
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s) IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub)
: base(sn, r, m, t,s,log) : base(sn, r, m, t,s,log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MailKit.Net.Smtp; using MailKit.Net.Smtp;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MimeKit; using MimeKit;
using Ombi.Core.Settings; using Ombi.Core.Settings;
@ -21,7 +22,7 @@ namespace Ombi.Notifications.Agents
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
{ {
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService<CustomizationSettings> c, public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, IEmailProvider prov, ISettingsService<CustomizationSettings> c,
ILogger<EmailNotification> log, UserManager<OmbiUser> um) : base(settings, r, m, t, c, log) ILogger<EmailNotification> log, UserManager<OmbiUser> um, IRepository<RequestSubscription> sub) : base(settings, r, m, t, c, log, sub)
{ {
EmailProvider = prov; EmailProvider = prov;
Logger = log; Logger = log;
@ -62,7 +63,7 @@ namespace Ombi.Notifications.Agents
return null; return null;
} }
var email = new EmailBasicTemplate(); 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 var message = new NotificationMessage
@ -227,10 +228,12 @@ namespace Ombi.Notifications.Agents
var plaintext = await LoadPlainTextMessage(NotificationType.RequestDeclined, model, settings); var plaintext = await LoadPlainTextMessage(NotificationType.RequestDeclined, model, settings);
message.Other.Add("PlainTextBody", plaintext); message.Other.Add("PlainTextBody", plaintext);
await SendToSubscribers(settings, message);
message.To = model.RequestType == RequestType.Movie message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email ? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email; : TvRequest.RequestedUser.Email;
await Send(message, settings); await Send(message, settings);
} }
protected override async Task RequestApproved(NotificationOptions model, EmailNotificationSettings 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); var plaintext = await LoadPlainTextMessage(NotificationType.RequestApproved, model, settings);
message.Other.Add("PlainTextBody", plaintext); message.Other.Add("PlainTextBody", plaintext);
await SendToSubscribers(settings, message);
message.To = model.RequestType == RequestType.Movie message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email ? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email; : TvRequest.RequestedUser.Email;
await Send(message, settings); 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) protected override async Task AvailableRequest(NotificationOptions model, EmailNotificationSettings settings)
{ {
var message = await LoadTemplate(NotificationType.RequestAvailable, model, 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); var plaintext = await LoadPlainTextMessage(NotificationType.RequestAvailable, model, settings);
message.Other.Add("PlainTextBody", plaintext); message.Other.Add("PlainTextBody", plaintext);
await SendToSubscribers(settings, message);
message.To = model.RequestType == RequestType.Movie message.To = model.RequestType == RequestType.Movie
? MovieRequest.RequestedUser.Email ? MovieRequest.RequestedUser.Email
: TvRequest.RequestedUser.Email; : TvRequest.RequestedUser.Email;

View file

@ -21,7 +21,7 @@ namespace Ombi.Notifications.Agents
public class MattermostNotification : BaseNotification<MattermostNotificationSettings>, IMattermostNotification public class MattermostNotification : BaseNotification<MattermostNotificationSettings>, IMattermostNotification
{ {
public MattermostNotification(IMattermostApi api, ISettingsService<MattermostNotificationSettings> sn, ILogger<MattermostNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, public MattermostNotification(IMattermostApi api, ISettingsService<MattermostNotificationSettings> sn, ILogger<MattermostNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
ISettingsService<CustomizationSettings> s) : base(sn, r, m, t,s,log) ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -22,7 +22,7 @@ namespace Ombi.Notifications.Agents
{ {
public MobileNotification(IOneSignalApi api, ISettingsService<MobileNotificationSettings> sn, ILogger<MobileNotification> log, INotificationTemplatesRepository r, public MobileNotification(IOneSignalApi api, ISettingsService<MobileNotificationSettings> sn, ILogger<MobileNotification> log, INotificationTemplatesRepository r,
IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<NotificationUserId> notification, IMovieRequestRepository m, ITvRequestRepository t, ISettingsService<CustomizationSettings> s, IRepository<NotificationUserId> notification,
UserManager<OmbiUser> um) : base(sn, r, m, t, s,log) UserManager<OmbiUser> um, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s,log, sub)
{ {
_api = api; _api = api;
_logger = log; _logger = log;
@ -167,6 +167,7 @@ namespace Ombi.Notifications.Agents
// Send to user // Send to user
var playerIds = GetUsers(model, NotificationType.RequestDeclined); var playerIds = GetUsers(model, NotificationType.RequestDeclined);
await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings); await Send(playerIds, notification, settings);
} }
@ -185,6 +186,8 @@ namespace Ombi.Notifications.Agents
// Send to user // Send to user
var playerIds = GetUsers(model, NotificationType.RequestApproved); var playerIds = GetUsers(model, NotificationType.RequestApproved);
await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings); await Send(playerIds, notification, settings);
} }
@ -202,6 +205,8 @@ namespace Ombi.Notifications.Agents
}; };
// Send to user // Send to user
var playerIds = GetUsers(model, NotificationType.RequestAvailable); var playerIds = GetUsers(model, NotificationType.RequestAvailable);
await AddSubscribedUsers(playerIds);
await Send(playerIds, notification, settings); await Send(playerIds, notification, settings);
} }
protected override Task Send(NotificationMessage model, MobileNotificationSettings settings) protected override Task Send(NotificationMessage model, MobileNotificationSettings settings)
@ -269,6 +274,20 @@ namespace Ombi.Notifications.Agents
return playerIds; return playerIds;
} }
private async Task AddSubscribedUsers(List<string> 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));
}
}
}
}
} }
} }

View file

@ -17,7 +17,7 @@ namespace Ombi.Notifications.Agents
public class PushbulletNotification : BaseNotification<PushbulletSettings>, IPushbulletNotification public class PushbulletNotification : BaseNotification<PushbulletSettings>, IPushbulletNotification
{ {
public PushbulletNotification(IPushbulletApi api, ISettingsService<PushbulletSettings> sn, ILogger<PushbulletNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, public PushbulletNotification(IPushbulletApi api, ISettingsService<PushbulletSettings> sn, ILogger<PushbulletNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
ISettingsService<CustomizationSettings> s) : base(sn, r, m, t,s,log) ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
public class PushoverNotification : BaseNotification<PushoverSettings>, IPushoverNotification public class PushoverNotification : BaseNotification<PushoverSettings>, IPushoverNotification
{ {
public PushoverNotification(IPushoverApi api, ISettingsService<PushoverSettings> sn, ILogger<PushoverNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, public PushoverNotification(IPushoverApi api, ISettingsService<PushoverSettings> sn, ILogger<PushoverNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
ISettingsService<CustomizationSettings> s) : base(sn, r, m, t, s, log) ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s, log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -18,7 +18,7 @@ namespace Ombi.Notifications.Agents
public class SlackNotification : BaseNotification<SlackNotificationSettings>, ISlackNotification public class SlackNotification : BaseNotification<SlackNotificationSettings>, ISlackNotification
{ {
public SlackNotification(ISlackApi api, ISettingsService<SlackNotificationSettings> sn, ILogger<SlackNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t, public SlackNotification(ISlackApi api, ISettingsService<SlackNotificationSettings> sn, ILogger<SlackNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t,
ISettingsService<CustomizationSettings> s) : base(sn, r, m, t, s, log) ISettingsService<CustomizationSettings> s, IRepository<RequestSubscription> sub) : base(sn, r, m, t, s, log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -18,7 +18,8 @@ namespace Ombi.Notifications.Agents
{ {
public TelegramNotification(ITelegramApi api, ISettingsService<TelegramSettings> sn, ILogger<TelegramNotification> log, public TelegramNotification(ITelegramApi api, ISettingsService<TelegramSettings> sn, ILogger<TelegramNotification> log,
INotificationTemplatesRepository r, IMovieRequestRepository m, INotificationTemplatesRepository r, IMovieRequestRepository m,
ITvRequestRepository t, ISettingsService<CustomizationSettings> s) : base(sn, r, m, t,s,log) ITvRequestRepository t, ISettingsService<CustomizationSettings> s
, IRepository<RequestSubscription> sub) : base(sn, r, m, t,s,log, sub)
{ {
Api = api; Api = api;
Logger = log; Logger = log;

View file

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -17,7 +19,7 @@ namespace Ombi.Notifications.Interfaces
public abstract class BaseNotification<T> : INotification where T : Settings.Settings.Models.Settings, new() public abstract class BaseNotification<T> : INotification where T : Settings.Settings.Models.Settings, new()
{ {
protected BaseNotification(ISettingsService<T> settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv, protected BaseNotification(ISettingsService<T> settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv,
ISettingsService<CustomizationSettings> customization, ILogger<BaseNotification<T>> log) ISettingsService<CustomizationSettings> customization, ILogger<BaseNotification<T>> log, IRepository<RequestSubscription> sub)
{ {
Settings = settings; Settings = settings;
TemplateRepository = templateRepo; TemplateRepository = templateRepo;
@ -26,6 +28,7 @@ namespace Ombi.Notifications.Interfaces
CustomizationSettings = customization; CustomizationSettings = customization;
Settings.ClearCache(); Settings.ClearCache();
CustomizationSettings.ClearCache(); CustomizationSettings.ClearCache();
RequestSubscription = sub;
_log = log; _log = log;
} }
@ -34,12 +37,14 @@ namespace Ombi.Notifications.Interfaces
protected IMovieRequestRepository MovieRepository { get; } protected IMovieRequestRepository MovieRepository { get; }
protected ITvRequestRepository TvRepository { get; } protected ITvRequestRepository TvRepository { get; }
protected CustomizationSettings Customization { get; set; } protected CustomizationSettings Customization { get; set; }
protected IRepository<RequestSubscription> RequestSubscription { get; set; }
private ISettingsService<CustomizationSettings> CustomizationSettings { get; } private ISettingsService<CustomizationSettings> CustomizationSettings { get; }
private readonly ILogger<BaseNotification<T>> _log; private readonly ILogger<BaseNotification<T>> _log;
protected ChildRequests TvRequest { get; set; } protected ChildRequests TvRequest { get; set; }
protected MovieRequests MovieRequest { get; set; } protected MovieRequests MovieRequest { get; set; }
protected IQueryable<OmbiUser> SubsribedUsers { get; private set; }
public abstract string NotificationName { get; } public abstract string NotificationName { get; }
@ -68,6 +73,7 @@ namespace Ombi.Notifications.Interfaces
if (model.RequestId > 0) if (model.RequestId > 0)
{ {
await LoadRequest(model.RequestId, model.RequestType); await LoadRequest(model.RequestId, model.RequestType);
SubsribedUsers = GetSubscriptions(model.RequestId, model.RequestType);
} }
Customization = await CustomizationSettings.GetSettingsAsync(); Customization = await CustomizationSettings.GetSettingsAsync();
@ -152,13 +158,19 @@ namespace Ombi.Notifications.Interfaces
} }
if (!template.Enabled) if (!template.Enabled)
{ {
return new NotificationMessageContent {Disabled = true}; return new NotificationMessageContent { Disabled = true };
} }
var parsed = Parse(model, template); var parsed = Parse(model, template);
return parsed; return parsed;
} }
protected IQueryable<OmbiUser> 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) private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template)
{ {
var resolver = new NotificationMessageResolver(); var resolver = new NotificationMessageResolver();

View file

@ -42,5 +42,6 @@ namespace Ombi.Store.Context
DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; } DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
DbSet<RequestLog> RequestLogs { get; set; } DbSet<RequestLog> RequestLogs { get; set; }
DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; } DbSet<RecentlyAddedLog> RecentlyAddedLogs { get; set; }
DbSet<RequestSubscription> RequestSubscription { get; set; }
} }
} }

View file

@ -47,6 +47,7 @@ namespace Ombi.Store.Context
public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; } public DbSet<SonarrEpisodeCache> SonarrEpisodeCache { get; set; }
public DbSet<SickRageCache> SickRageCache { get; set; } public DbSet<SickRageCache> SickRageCache { get; set; }
public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; } public DbSet<SickRageEpisodeCache> SickRageEpisodeCache { get; set; }
public DbSet<RequestSubscription> RequestSubscription { get; set; }
public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; } public DbSet<ApplicationConfiguration> ApplicationConfigurations { get; set; }

View file

@ -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; }
}
}

View file

@ -12,6 +12,9 @@ namespace Ombi.Store.Entities.Requests
[ForeignKey(nameof(IssueId))] [ForeignKey(nameof(IssueId))]
public List<Issues> Issues { get; set; } public List<Issues> Issues { get; set; }
[NotMapped]
public bool Subscribed { get; set; }
public int RootPathOverride { get; set; } public int RootPathOverride { get; set; }
public int QualityOverride { get; set; } public int QualityOverride { get; set; }
} }

View file

@ -16,6 +16,12 @@ namespace Ombi.Store.Entities.Requests
public string Background { get; set; } public string Background { get; set; }
public DateTime ReleaseDate { get; set; } public DateTime ReleaseDate { get; set; }
public string Status { get; set; } public string Status { get; set; }
/// <summary>
/// This is to see if the user is subscribed in the UI
/// </summary>
[NotMapped]
public bool Subscribed { get; set; }
/// <summary> /// <summary>
/// This is so we can correctly send the right amount of seasons to Sonarr /// This is so we can correctly send the right amount of seasons to Sonarr
/// </summary> /// </summary>

View file

@ -0,0 +1,981 @@
// <auto-generated />
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<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Type");
b.Property<string>("Value");
b.HasKey("Id");
b.ToTable("ApplicationConfiguration");
});
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AuditArea");
b.Property<int>("AuditType");
b.Property<DateTime>("DateTime");
b.Property<string>("Description");
b.Property<string>("User");
b.HasKey("Id");
b.ToTable("Audit");
});
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TheMovieDbId");
b.HasKey("Id");
b.ToTable("CouchPotatoCache");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("EmbyId")
.IsRequired();
b.Property<string>("ImdbId");
b.Property<string>("ProviderId");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.Property<int>("Type");
b.Property<string>("Url");
b.HasKey("Id");
b.ToTable("EmbyContent");
});
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("EmbyId");
b.Property<int>("EpisodeNumber");
b.Property<string>("ImdbId");
b.Property<string>("ParentId");
b.Property<string>("ProviderId");
b.Property<int>("SeasonNumber");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.HasKey("Id");
b.HasIndex("ParentId");
b.ToTable("EmbyEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Content");
b.Property<string>("SettingsName");
b.HasKey("Id");
b.ToTable("GlobalSettings");
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("Agent");
b.Property<bool>("Enabled");
b.Property<string>("Message");
b.Property<int>("NotificationType");
b.Property<string>("Subject");
b.HasKey("Id");
b.ToTable("NotificationTemplates");
});
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("PlayerId");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("NotificationUserId");
});
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("Alias");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<string>("EmbyConnectUserId");
b.Property<int?>("EpisodeRequestLimit");
b.Property<DateTime?>("LastLoggedIn");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<int?>("MovieRequestLimit");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("ProviderUserId");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserAccessToken");
b.Property<string>("UserName")
.HasMaxLength(256);
b.Property<int>("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<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<int>("GrandparentKey");
b.Property<int>("Key");
b.Property<int>("ParentKey");
b.Property<int>("SeasonNumber");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("GrandparentKey");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ParentKey");
b.Property<int>("PlexContentId");
b.Property<int?>("PlexServerContentId");
b.Property<int>("SeasonKey");
b.Property<int>("SeasonNumber");
b.HasKey("Id");
b.HasIndex("PlexServerContentId");
b.ToTable("PlexSeasonsContent");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<string>("ImdbId");
b.Property<int>("Key");
b.Property<string>("Quality");
b.Property<string>("ReleaseYear");
b.Property<string>("TheMovieDbId");
b.Property<string>("Title");
b.Property<string>("TvDbId");
b.Property<int>("Type");
b.Property<string>("Url");
b.HasKey("Id");
b.ToTable("PlexServerContent");
});
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("HasFile");
b.Property<int>("TheMovieDbId");
b.HasKey("Id");
b.ToTable("RadarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedAt");
b.Property<int>("ContentId");
b.Property<int>("ContentType");
b.Property<int?>("EpisodeNumber");
b.Property<int?>("SeasonNumber");
b.Property<int>("Type");
b.HasKey("Id");
b.ToTable("RecentlyAddedLog");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<bool?>("Denied");
b.Property<string>("DeniedReason");
b.Property<int?>("IssueId");
b.Property<int>("ParentRequestId");
b.Property<int>("RequestType");
b.Property<DateTime>("RequestedDate");
b.Property<string>("RequestedUserId");
b.Property<int>("SeriesType");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("ParentRequestId");
b.HasIndex("RequestedUserId");
b.ToTable("ChildRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Value");
b.HasKey("Id");
b.ToTable("IssueCategory");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Comment");
b.Property<DateTime>("Date");
b.Property<int?>("IssuesId");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("IssuesId");
b.HasIndex("UserId");
b.ToTable("IssueComments");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Description");
b.Property<int>("IssueCategoryId");
b.Property<int?>("IssueId");
b.Property<string>("ProviderId");
b.Property<int?>("RequestId");
b.Property<int>("RequestType");
b.Property<DateTime?>("ResovledDate");
b.Property<int>("Status");
b.Property<string>("Subject");
b.Property<string>("Title");
b.Property<string>("UserReportedId");
b.HasKey("Id");
b.HasIndex("IssueCategoryId");
b.HasIndex("IssueId");
b.HasIndex("UserReportedId");
b.ToTable("Issues");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<string>("Background");
b.Property<bool?>("Denied");
b.Property<string>("DeniedReason");
b.Property<DateTime?>("DigitalReleaseDate");
b.Property<string>("ImdbId");
b.Property<int?>("IssueId");
b.Property<string>("Overview");
b.Property<string>("PosterPath");
b.Property<int>("QualityOverride");
b.Property<DateTime>("ReleaseDate");
b.Property<int>("RequestType");
b.Property<DateTime>("RequestedDate");
b.Property<string>("RequestedUserId");
b.Property<int>("RootPathOverride");
b.Property<string>("Status");
b.Property<int>("TheMovieDbId");
b.Property<string>("Title");
b.HasKey("Id");
b.HasIndex("RequestedUserId");
b.ToTable("MovieRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeCount");
b.Property<DateTime>("RequestDate");
b.Property<int>("RequestId");
b.Property<int>("RequestType");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RequestLog");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Background");
b.Property<string>("ImdbId");
b.Property<string>("Overview");
b.Property<string>("PosterPath");
b.Property<int?>("QualityOverride");
b.Property<DateTime>("ReleaseDate");
b.Property<int?>("RootFolder");
b.Property<string>("Status");
b.Property<string>("Title");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("TvRequests");
});
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("RequestId");
b.Property<int>("RequestType");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RequestSubscription");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SickRageCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<int>("SeasonNumber");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SickRageEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SonarrCache");
});
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<bool>("HasFile");
b.Property<int>("SeasonNumber");
b.Property<int>("TvDbId");
b.HasKey("Id");
b.ToTable("SonarrEpisodeCache");
});
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Token");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Tokens");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AirDate");
b.Property<bool>("Approved");
b.Property<bool>("Available");
b.Property<int>("EpisodeNumber");
b.Property<bool>("Requested");
b.Property<int>("SeasonId");
b.Property<string>("Title");
b.Property<string>("Url");
b.HasKey("Id");
b.HasIndex("SeasonId");
b.ToTable("EpisodeRequests");
});
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("ChildRequestId");
b.Property<int>("SeasonNumber");
b.HasKey("Id");
b.HasIndex("ChildRequestId");
b.ToTable("SeasonRequests");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", 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<string>", 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.NotificationUserId", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
.WithMany("NotificationUserIds")
.HasForeignKey("UserId");
});
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");
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
.WithMany()
.HasForeignKey("UserReportedId");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
.WithMany()
.HasForeignKey("RequestedUserId");
});
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
.WithMany()
.HasForeignKey("UserId");
});
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "user")
.WithMany()
.HasForeignKey("UserId");
});
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
}
}
}

View file

@ -0,0 +1,44 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace Ombi.Store.Migrations
{
public partial class RequestSubscription : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "RequestSubscription",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
RequestId = table.Column<int>(nullable: false),
RequestType = table.Column<int>(nullable: false),
UserId = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RequestSubscription", x => x.Id);
table.ForeignKey(
name: "FK_RequestSubscription_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_RequestSubscription_UserId",
table: "RequestSubscription",
column: "UserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "RequestSubscription");
}
}
}

View file

@ -20,7 +20,7 @@ namespace Ombi.Store.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011"); .HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{ {
@ -676,6 +676,24 @@ namespace Ombi.Store.Migrations
b.ToTable("TvRequests"); b.ToTable("TvRequests");
}); });
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("RequestId");
b.Property<int>("RequestType");
b.Property<string>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RequestSubscription");
});
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b => modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -927,6 +945,13 @@ namespace Ombi.Store.Migrations
.HasForeignKey("UserId"); .HasForeignKey("UserId");
}); });
modelBuilder.Entity("Ombi.Store.Entities.RequestSubscription", b =>
{
b.HasOne("Ombi.Store.Entities.OmbiUser", "user")
.WithMany()
.HasForeignKey("UserId");
});
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
{ {
b.HasOne("Ombi.Store.Entities.OmbiUser", "User") b.HasOne("Ombi.Store.Entities.OmbiUser", "User")

View file

@ -12,6 +12,7 @@ export interface IMovieRequests extends IFullBaseRequest {
rootPathOverride: number; rootPathOverride: number;
qualityOverride: number; qualityOverride: number;
digitalReleaseDate: Date; digitalReleaseDate: Date;
subscribed: boolean;
// For the UI // For the UI
rootPathOverrideTitle: string; rootPathOverrideTitle: string;

View file

@ -124,7 +124,13 @@
</div> </div>
</div> </div>
<div class="col-sm-3 col-sm-push-3 small-padding"> <div class="col-sm-2 col-sm-push-3 small-padding">
<div style="float:right">
<a *ngIf="!request.subscribed" style="color:white" (click)="subscribe(request)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="request.subscribed" style="color:red" (click)="unSubscribe(request)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a>
</div>
<div *ngIf="isAdmin"> <div *ngIf="isAdmin">
<div *ngIf="!request.approved" id="approveBtn"> <div *ngIf="!request.approved" id="approveBtn">
<form> <form>
@ -189,7 +195,6 @@
</div> </div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn"> <div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" <button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true"> aria-expanded="true">

View file

@ -209,6 +209,22 @@ export class MovieRequestsComponent implements OnInit {
this.order = value; this.order = value;
} }
public subscribe(request: IMovieRequests) {
request.subscribed = true;
this.requestService.subscribeToMovie(request.id)
.subscribe(x => {
this.notificationService.success("Subscribed To Movie!");
});
}
public unSubscribe(request: IMovieRequests) {
request.subscribed = false;
this.requestService.subscribeToMovie(request.id)
.subscribe(x => {
this.notificationService.success("Unsubscribed Movie!");
});
}
private filterActiveStyle(el: any) { private filterActiveStyle(el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement; el = el.toElement || el.relatedTarget || el.target || el.srcElement;

View file

@ -13,7 +13,7 @@ import { RequestComponent } from "./request.component";
import { TvRequestChildrenComponent } from "./tvrequest-children.component"; import { TvRequestChildrenComponent } from "./tvrequest-children.component";
import { TvRequestsComponent } from "./tvrequests.component"; import { TvRequestsComponent } from "./tvrequests.component";
import { SidebarModule, TreeTableModule } from "primeng/primeng"; import { SidebarModule, TooltipModule, TreeTableModule } from "primeng/primeng";
import { IdentityService, RadarrService, RequestService, SonarrService } from "../services"; import { IdentityService, RadarrService, RequestService, SonarrService } from "../services";
@ -37,6 +37,7 @@ const routes: Routes = [
SidebarModule, SidebarModule,
OrderModule, OrderModule,
PaginatorModule, PaginatorModule,
TooltipModule,
], ],
declarations: [ declarations: [
RequestComponent, RequestComponent,

View file

@ -117,4 +117,17 @@ export class RequestService extends ServiceHelpers {
public filterMovies(filter: IFilter): Observable<IFilterResult<IMovieRequests>> { public filterMovies(filter: IFilter): Observable<IFilterResult<IMovieRequests>> {
return this.http.post<IFilterResult<IMovieRequests>>(`${this.url}movie/filter`, JSON.stringify(filter), {headers: this.headers}); return this.http.post<IFilterResult<IMovieRequests>>(`${this.url}movie/filter`, JSON.stringify(filter), {headers: this.headers});
} }
public subscribeToMovie(requestId: number): Observable<boolean> {
return this.http.post<boolean>(`${this.url}movie/subscribe/${requestId}`, {headers: this.headers});
}
public unSubscribeToMovie(requestId: number): Observable<boolean> {
return this.http.post<boolean>(`${this.url}movie/unsubscribe/${requestId}`, {headers: this.headers});
}
public subscribeToTv(requestId: number): Observable<boolean> {
return this.http.post<boolean>(`${this.url}tv/subscribe/${requestId}`, {headers: this.headers});
}
public unSubscribeToTv(requestId: number): Observable<boolean> {
return this.http.post<boolean>(`${this.url}tv/unsubscribe/${requestId}`, {headers: this.headers});
}
} }

View file

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Ombi.Store.Entities.Requests; using Ombi.Store.Entities.Requests;
using System.Diagnostics; using System.Diagnostics;
using Ombi.Models; using Ombi.Models;
using Ombi.Store.Entities;
namespace Ombi.Controllers namespace Ombi.Controllers
{ {
@ -356,5 +357,45 @@ namespace Ombi.Controllers
{ {
return await MovieRequestEngine.Filter(vm); return await MovieRequestEngine.Filter(vm);
} }
/// <summary>
/// Subscribes for notifications to a movie request
/// </summary>
[HttpPost("movie/subscribe/{requestId:int}")]
public async Task<bool> SubscribeToMovie(int requestId)
{
await MovieRequestEngine.SubscribeToRequest(requestId, RequestType.Movie);
return true;
}
/// <summary>
/// Subscribes for notifications to a TV request
/// </summary>
[HttpPost("tv/subscribe/{requestId:int}")]
public async Task<bool> SubscribeToTv(int requestId)
{
await TvRequestEngine.SubscribeToRequest(requestId, RequestType.TvShow);
return true;
}
/// <summary>
/// UnSubscribes for notifications to a movie request
/// </summary>
[HttpPost("movie/unsubscribe/{requestId:int}")]
public async Task<bool> UnSubscribeToMovie(int requestId)
{
await MovieRequestEngine.UnSubscribeRequest(requestId, RequestType.Movie);
return true;
}
/// <summary>
/// UnSubscribes for notifications to a TV request
/// </summary>
[HttpPost("tv/unsubscribe/{requestId:int}")]
public async Task<bool> UnSubscribeToTv(int requestId)
{
await TvRequestEngine.UnSubscribeRequest(requestId, RequestType.TvShow);
return true;
}
} }
} }