Commit 181bd532 authored by tidusjar's avatar tidusjar

Fixed the notifications issue

parent 96e3e882
......@@ -318,7 +318,7 @@ namespace Ombi.Core.Engine
request.Denied = true;
request.DeniedReason = denyReason;
// We are denying a request
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await MovieRepository.Update(request);
return new RequestEngineResult
......@@ -346,7 +346,7 @@ namespace Ombi.Core.Engine
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
if (canNotify.Success)
{
NotificationHelper.Notify(request, NotificationType.RequestApproved);
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
}
if (request.Approved)
......@@ -462,7 +462,7 @@ namespace Ombi.Core.Engine
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MovieRepository.Update(request);
return new RequestEngineResult
......@@ -478,8 +478,8 @@ namespace Ombi.Core.Engine
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (result.Success)
{
NotificationHelper.NewRequest(model);
{
await NotificationHelper.NewRequest(model);
}
await _requestLog.Add(new RequestLog
......
......@@ -314,7 +314,7 @@ namespace Ombi.Core.Engine
request.Denied = true;
request.DeniedReason = reason;
// We are denying a request
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await MusicRepository.Update(request);
return new RequestEngineResult
......@@ -342,7 +342,7 @@ namespace Ombi.Core.Engine
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
if (canNotify.Success)
{
NotificationHelper.Notify(request, NotificationType.RequestApproved);
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
}
if (request.Approved)
......@@ -469,7 +469,7 @@ namespace Ombi.Core.Engine
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MusicRepository.Update(request);
return new RequestEngineResult
......@@ -486,7 +486,7 @@ namespace Ombi.Core.Engine
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (result.Success)
{
NotificationHelper.NewRequest(model);
await NotificationHelper.NewRequest(model);
}
await _requestLog.Add(new RequestLog
......
......@@ -159,7 +159,6 @@ namespace Ombi.Core.Engine
}
await CheckForSubscription(shouldHide, allRequests);
allRequests.ForEach(async r => { });
return new RequestsViewModel<TvRequests>
{
......@@ -389,7 +388,7 @@ namespace Ombi.Core.Engine
if (request.Approved)
{
NotificationHelper.Notify(request, NotificationType.RequestApproved);
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
// Autosend
await TvSender.Send(request);
}
......@@ -412,7 +411,7 @@ namespace Ombi.Core.Engine
request.Denied = true;
request.DeniedReason = reason;
await TvRepository.UpdateChild(request);
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await NotificationHelper.Notify(request, NotificationType.RequestDeclined);
return new RequestEngineResult
{
Result = true
......@@ -500,7 +499,7 @@ namespace Ombi.Core.Engine
}
}
await TvRepository.UpdateChild(request);
NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
return new RequestEngineResult
{
Result = true,
......@@ -585,7 +584,7 @@ namespace Ombi.Core.Engine
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (sendRuleResult.Success)
{
NotificationHelper.NewRequest(model);
await NotificationHelper.NewRequest(model);
}
await _requestLog.Add(new RequestLog
......@@ -600,7 +599,7 @@ namespace Ombi.Core.Engine
if (model.Approved)
{
// Autosend
NotificationHelper.Notify(model, NotificationType.RequestApproved);
await NotificationHelper.Notify(model, NotificationType.RequestApproved);
var result = await TvSender.Send(model);
if (result.Success)
{
......
using System;
using Hangfire;
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Notifications.Models;
......@@ -9,13 +10,7 @@ namespace Ombi.Core
{
public class NotificationHelper : INotificationHelper
{
public NotificationHelper(INotificationService service)
{
NotificationService = service;
}
private INotificationService NotificationService { get; }
public void NewRequest(FullBaseRequest model)
public async Task NewRequest(FullBaseRequest model)
{
var notificationModel = new NotificationOptions
{
......@@ -24,11 +19,13 @@ namespace Ombi.Core
NotificationType = NotificationType.NewRequest,
RequestType = model.RequestType
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public void NewRequest(ChildRequests model)
public async Task NewRequest(ChildRequests model)
{
var notificationModel = new NotificationOptions
{
......@@ -36,11 +33,14 @@ namespace Ombi.Core
DateTime = DateTime.Now,
NotificationType = NotificationType.NewRequest,
RequestType = model.RequestType
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
};
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public void NewRequest(AlbumRequest model)
public async Task NewRequest(AlbumRequest model)
{
var notificationModel = new NotificationOptions
{
......@@ -48,12 +48,15 @@ namespace Ombi.Core
DateTime = DateTime.Now,
NotificationType = NotificationType.NewRequest,
RequestType = model.RequestType
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
};
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public void Notify(MovieRequests model, NotificationType type)
public async Task Notify(MovieRequests model, NotificationType type)
{
var notificationModel = new NotificationOptions
{
......@@ -63,10 +66,13 @@ namespace Ombi.Core
RequestType = model.RequestType,
Recipient = model.RequestedUser?.Email ?? string.Empty
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public void Notify(ChildRequests model, NotificationType type)
public async Task Notify(ChildRequests model, NotificationType type)
{
var notificationModel = new NotificationOptions
{
......@@ -76,10 +82,13 @@ namespace Ombi.Core
RequestType = model.RequestType,
Recipient = model.RequestedUser?.Email ?? string.Empty
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public void Notify(AlbumRequest model, NotificationType type)
public async Task Notify(AlbumRequest model, NotificationType type)
{
var notificationModel = new NotificationOptions
{
......@@ -90,7 +99,18 @@ namespace Ombi.Core
Recipient = model.RequestedUser?.Email ?? string.Empty
};
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, notificationModel}
});
}
public async Task Notify(NotificationOptions model)
{
await OmbiQuartz.TriggerJob(nameof(INotificationService), "Notifications", new Dictionary<string, object>
{
{JobDataKeys.NotificationOptions, model}
});
}
}
}
\ No newline at end of file
using Ombi.Core.Models.Requests;
using System.Threading.Tasks;
using Ombi.Core.Models.Requests;
using Ombi.Helpers;
using Ombi.Notifications.Models;
using Ombi.Store.Entities.Requests;
namespace Ombi.Core
{
public interface INotificationHelper
{
void NewRequest(FullBaseRequest model);
void NewRequest(ChildRequests model);
void NewRequest(AlbumRequest model);
void Notify(MovieRequests model, NotificationType type);
void Notify(ChildRequests model, NotificationType type);
void Notify(AlbumRequest model, NotificationType type);
Task NewRequest(FullBaseRequest model);
Task NewRequest(ChildRequests model);
Task NewRequest(AlbumRequest model);
Task Notify(MovieRequests model, NotificationType type);
Task Notify(ChildRequests model, NotificationType type);
Task Notify(AlbumRequest model, NotificationType type);
Task Notify(NotificationOptions model);
}
}
\ No newline at end of file
......@@ -95,7 +95,7 @@ namespace Ombi.Core.Senders
Type = RequestType.Movie,
RetryCount = 0
});
_notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
await _notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
}
}
......
......@@ -65,7 +65,7 @@ namespace Ombi.Core.Senders
Type = RequestType.Album,
RetryCount = 0
});
_notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
await _notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
}
}
......
......@@ -128,7 +128,7 @@ namespace Ombi.Core.Senders
Type = RequestType.TvShow,
RetryCount = 0
});
_notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
await _notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
}
}
......
......@@ -181,7 +181,8 @@ namespace Ombi.DependencyInjection
public static void RegisterJobs(this IServiceCollection services)
{
services.AddSingleton<IJobFactory, IoCJobFactory>(provider => new IoCJobFactory(provider));
services.AddSingleton<QuartzJobRunner>();
services.AddSingleton<IJobFactory, IoCJobFactory>();
services.AddTransient<IBackgroundJobClient, BackgroundJobClient>();
services.AddTransient<IPlexContentSync, PlexContentSync>();
......
namespace Ombi.Schedule
namespace Ombi.Helpers
{
public class JobDataKeys
{
public const string RecentlyAddedSearch = "recentlyAddedSearch";
public const string NotificationOptions = nameof(NotificationOptions);
}
}
\ No newline at end of file
......@@ -14,6 +14,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
<PackageReference Include="Quartz" Version="3.0.7" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
</ItemGroup>
......
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Helpers;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
namespace Ombi.Schedule
namespace Ombi.Helpers
{
public class OmbiQuartz
{
......@@ -78,7 +77,12 @@ namespace Ombi.Schedule
{
await Scheduler.TriggerJob(new JobKey(jobName, group));
}
public static async Task TriggerJob(string jobName, string group, IDictionary<string, object> data)
{
await Scheduler.TriggerJob(new JobKey(jobName, group), new JobDataMap(data));
}
public static async Task Start()
{
await Scheduler.Start();
......
using System.Threading.Tasks;
using Ombi.Notifications;
using Ombi.Notifications.Models;
using Quartz;
namespace Ombi.Core.Notifications
{
public interface INotificationService
public interface INotificationService : IJob
{
Task Publish(NotificationOptions model);
Task Publish(NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings);
Task PublishTest(NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings, INotification type);
}
}
\ No newline at end of file
......@@ -7,78 +7,46 @@ using Microsoft.Extensions.Logging;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Notifications.Models;
using Quartz;
namespace Ombi.Notifications
{
public class NotificationService : INotificationService
{
private readonly IServiceProvider _provider;
public NotificationService(IServiceProvider provider, ILogger<NotificationService> log)
{
_provider = provider;
Log = log;
NotificationAgents = new List<INotification>();
var baseSearchType = typeof(BaseNotification<>).Name;
var ass = typeof(NotificationService).GetTypeInfo().Assembly;
foreach (var ti in ass.DefinedTypes)
{
if (ti?.BaseType?.Name == baseSearchType)
{
var type = ti?.AsType();
var ctors = type.GetConstructors();
var ctor = ctors.FirstOrDefault();
var services = new List<object>();
foreach (var param in ctor.GetParameters())
{
services.Add(provider.GetService(param.ParameterType));
}
var item = Activator.CreateInstance(type, services.ToArray());
NotificationAgents.Add((INotification)item);
}
}
PopulateAgents();
}
private List<INotification> NotificationAgents { get; }
private ILogger<NotificationService> Log { get; }
/// <summary>^
/// <summary>
/// Sends a notification to the user. This one is used in normal notification scenarios
/// </summary>
/// <param name="model">The model.</param>
/// <param name="context">The model.</param>
/// <returns></returns>
public async Task Publish(NotificationOptions model)
public async Task Execute(IJobExecutionContext context)
{
var notificationTasks = new List<Task>();
JobDataMap dataMap = context.MergedJobDataMap;
var model = (NotificationOptions)dataMap.Get(JobDataKeys.NotificationOptions);
foreach (var agent in NotificationAgents)
{
notificationTasks.Add(NotifyAsync(agent,model));
await NotifyAsync(agent, model);
}
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
}
/// <summary>
/// Sends a notification to the user, this is usually for testing the settings.
/// </summary>
/// <param name="model">The model.</param>
/// <param name="settings">The settings.</param>
/// <returns></returns>
public async Task Publish(NotificationOptions model, Settings.Settings.Models.Settings settings)
{
var notificationTasks = NotificationAgents.Select(notification => NotifyAsync(notification, model, settings));
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
}
private async Task NotifyAsync(INotification notification, NotificationOptions model)
{
try
{
await notification.NotifyAsync(model).ConfigureAwait(false);
await notification.NotifyAsync(model);
}
catch (Exception ex)
{
......@@ -86,26 +54,31 @@ namespace Ombi.Notifications
}
}
private async Task NotifyAsync(INotification notification, NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings)
private void PopulateAgents()
{
if (model.RequestId == 0)
{
throw new ArgumentException("RequestId is not set");
}
try
{
await notification.NotifyAsync(model, settings).ConfigureAwait(false);
}
catch (Exception ex)
var baseSearchType = typeof(BaseNotification<>).Name;
var ass = typeof(NotificationService).GetTypeInfo().Assembly;
foreach (var ti in ass.DefinedTypes)
{
throw new InvalidOperationException(ex.Message);
}
}
if (ti?.BaseType?.Name == baseSearchType)
{
var type = ti?.AsType();
var ctors = type.GetConstructors();
var ctor = ctors.FirstOrDefault();
public async Task PublishTest(NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings, INotification type)
{
await type.NotifyAsync(model, settings);
var services = new List<object>();
foreach (var param in ctor.GetParameters())
{
services.Add(_provider.GetService(param.ParameterType));
}
var item = Activator.CreateInstance(type, services.ToArray());
NotificationAgents.Add((INotification)item);
}
}
}
}
}
\ No newline at end of file
......@@ -7,26 +7,18 @@ namespace Ombi.Schedule
{
public class IoCJobFactory : IJobFactory
{
private readonly IServiceProvider _factory;
public IoCJobFactory(IServiceProvider factory)
private readonly IServiceProvider _serviceProvider;
public IoCJobFactory(IServiceProvider serviceProvider)
{
_factory = factory;
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var scopeFactory = _factory.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var scopedContainer = scope.ServiceProvider;
var implementation = scopedContainer.GetRequiredService(bundle.JobDetail.JobType) as IJob;
return implementation;
return _serviceProvider.GetRequiredService<QuartzJobRunner>();
}
public void ReturnJob(IJob job)
{
var disposable = job as IDisposable;
disposable?.Dispose();
}
}
}
\ No newline at end of file
......@@ -31,6 +31,7 @@ using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Notifications.Models;
......@@ -45,7 +46,7 @@ namespace Ombi.Schedule.Jobs.Emby
public class EmbyAvaliabilityChecker : IEmbyAvaliabilityChecker
{
public EmbyAvaliabilityChecker(IEmbyContentRepository repo, ITvRequestRepository t, IMovieRequestRepository m,
INotificationService n, ILogger<EmbyAvaliabilityChecker> log)
INotificationHelper n, ILogger<EmbyAvaliabilityChecker> log)
{
_repo = repo;
_tvRepo = t;
......@@ -57,7 +58,7 @@ namespace Ombi.Schedule.Jobs.Emby
private readonly ITvRequestRepository _tvRepo;
private readonly IMovieRequestRepository _movieRepo;
private readonly IEmbyContentRepository _repo;
private readonly INotificationService _notificationService;
private readonly INotificationHelper _notificationService;
private readonly ILogger<EmbyAvaliabilityChecker> _log;
public async Task Execute(IJobExecutionContext job)
......@@ -100,14 +101,14 @@ namespace Ombi.Schedule.Jobs.Emby
_log.LogDebug("MovieId: {0}, RequestUser: {1}", movie.Id, recipient);
BackgroundJob.Enqueue(() => _notificationService.Publish(new NotificationOptions
await _notificationService.Notify(new NotificationOptions
{
DateTime = DateTime.Now,
NotificationType = NotificationType.RequestAvailable,
RequestId = movie.Id,
RequestType = RequestType.Movie,
Recipient = recipient,
}));
});
}
}
await _movieRepo.Save();
......@@ -191,14 +192,14 @@ namespace Ombi.Schedule.Jobs.Emby
// We have fulfulled this request!
child.Available = true;
child.MarkedAsAvailable = DateTime.Now;
BackgroundJob.Enqueue(() => _notificationService.Publish(new NotificationOptions
await _notificationService.Notify(new NotificationOptions
{
DateTime = DateTime.Now,
NotificationType = NotificationType.RequestAvailable,
RequestId = child.Id,
RequestType = RequestType.TvShow,
Recipient = child.RequestedUser.Email
}));
});
}
}
......
......@@ -34,6 +34,7 @@ using Microsoft.Extensions.Logging;
using Ombi.Api.Emby;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Quartz;
......
......@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Notifications.Models;
......@@ -18,7 +19,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
public class LidarrAvailabilityChecker : ILidarrAvailabilityChecker
{
public LidarrAvailabilityChecker(IMusicRequestRepository requests, IRepository<LidarrAlbumCache> albums, ILogger<LidarrAvailabilityChecker> log,
IBackgroundJobClient job, INotificationService notification)
IBackgroundJobClient job, INotificationHelper notification)
{
_cachedAlbums = albums;
_requestRepository = requests;
......@@ -31,7 +32,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
private readonly IRepository<LidarrAlbumCache> _cachedAlbums;
private readonly ILogger _logger;
private readonly IBackgroundJobClient _job;
private readonly INotificationService _notificationService;
private readonly INotificationHelper _notificationService;
public async Task Start()
{
......@@ -59,14 +60,15 @@ namespace Ombi.Schedule.Jobs.Lidarr
_logger.LogDebug("AlbumId: {0}, RequestUser: {1}", albumRequest.Id, recipient);
_job.Enqueue(() => _notificationService.Publish(new NotificationOptions
await _notificationService.Notify(new NotificationOptions
{
DateTime = DateTime.Now,
NotificationType = NotificationType.RequestAvailable,
RequestId = albumRequest.Id,
RequestType = RequestType.Album,
Recipient = recipient,
}));
});
}
}
}
......
......@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Hangfire;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ombi.Core;
using Ombi.Core.Notifications;
using Ombi.Helpers;
using Ombi.Notifications.Models;
......@@ -19,7 +20,7 @@ namespace Ombi.Schedule.Jobs.Plex
public class PlexAvailabilityChecker : IPlexAvailabilityChecker
{
public PlexAvailabilityChecker(IPlexContentRepository repo, ITvRequestRepository tvRequest, IMovieRequestRepository movies,
INotificationService notification, IBackgroundJobClient background, ILogger<PlexAvailabilityChecker> log)
INotificationHelper notification, IBackgroundJobClient background, ILogger<PlexAvailabilityChecker> log)
{
_tvRepo = tvRequest;
_repo = repo;
......@@ -32,7 +33,7 @@ namespace Ombi.Schedule.Jobs.Plex
private readonly ITvRequestRepository _tvRepo;
private readonly IMovieRequestRepository _movieRepo;
private readonly IPlexContentRepository _repo;
private readonly INotificationService _notificationService;
private readonly INotificationHelper _notificationService;
private readonly IBackgroundJobClient _backgroundJobClient;
private readonly ILogger _log;
......@@ -126,7 +127,8 @@ namespace Ombi.Schedule.Jobs.Plex
// We have ful-fulled this request!
child.Available = true;
child.MarkedAsAvailable = DateTime.Now;
await _notificationService.Publish(new NotificationOptions
await _notificationService.Notify(new NotificationOptions