using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Notifications.Exceptions; using Ombi.Notifications.Models; using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; using Ombi.Store.Repository; using Ombi.Store.Repository.Requests; namespace Ombi.Notifications { 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, IRepository sub, IMusicRequestRepository album, IRepository notificationUserPreferences, UserManager um) { Settings = settings; TemplateRepository = templateRepo; MovieRepository = movie; TvRepository = tv; CustomizationSettings = customization; RequestSubscription = sub; _log = log; AlbumRepository = album; UserNotificationPreferences = notificationUserPreferences; _userManager = um; Settings?.ClearCache(); } protected ISettingsService Settings { get; } protected INotificationTemplatesRepository TemplateRepository { get; } protected IMovieRequestRepository MovieRepository { get; } protected ITvRequestRepository TvRepository { get; } protected IMusicRequestRepository AlbumRepository { get; } protected CustomizationSettings Customization { get; set; } protected IRepository RequestSubscription { get; set; } protected IRepository UserNotificationPreferences { get; set; } private ISettingsService CustomizationSettings { get; } private readonly ILogger> _log; private readonly UserManager _userManager; protected ChildRequests TvRequest { get; set; } protected AlbumRequest AlbumRequest { get; set; } protected MovieRequests MovieRequest { get; set; } protected IQueryable Subscribed { get; private set; } public abstract string NotificationName { get; } public async Task NotifyAsync(NotificationOptions model) { var configuration = await GetConfiguration(); await NotifyAsync(model, configuration); } public async Task NotifyAsync(NotificationOptions model, Settings.Settings.Models.Settings settings) { if (settings == null) { await NotifyAsync(model); return; } 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); Subscribed = GetSubscriptions(model.RequestId, model.RequestType); } Customization = await CustomizationSettings.GetSettingsAsync(); try { switch (model.NotificationType) { case NotificationType.NewRequest: await NewRequest(model, notificationSettings); break; case NotificationType.Issue: await NewIssue(model, notificationSettings); break; case NotificationType.RequestAvailable: await AvailableRequest(model, notificationSettings); break; case NotificationType.RequestApproved: await RequestApproved(model, notificationSettings); break; case NotificationType.Test: await Test(model, notificationSettings); break; case NotificationType.RequestDeclined: await RequestDeclined(model, notificationSettings); break; case NotificationType.ItemAddedToFaultQueue: await AddedToRequestQueue(model, notificationSettings); break; case NotificationType.IssueResolved: await IssueResolved(model, notificationSettings); break; case NotificationType.IssueComment: await IssueComment(model, notificationSettings); break; case NotificationType.PartiallyAvailable: await PartiallyAvailable(model, notificationSettings); break; case NotificationType.AdminNote: case NotificationType.WelcomeEmail: case NotificationType.Newsletter: break; default: throw new ArgumentOutOfRangeException(); } } catch (NotImplementedException) { // Do nothing, it's not implimented meaning it might not be ready or even used } } /// /// Loads the TV or Movie Request /// /// /// /// protected virtual async Task LoadRequest(int requestId, RequestType type) { if (type == RequestType.Movie) { MovieRequest = await MovieRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId); } else if (type == RequestType.TvShow) { TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId); } else if (type == RequestType.Album) { AlbumRequest = await AlbumRepository.GetWithUser().FirstOrDefaultAsync(x => x.Id == requestId); } } private async Task GetConfiguration() { var settings = await Settings.GetSettingsAsync(); return settings; } /// /// Loads the correct template from the DB /// /// /// /// /// protected virtual async Task LoadTemplate(NotificationAgent agent, NotificationType type, NotificationOptions model) { var template = await TemplateRepository.GetTemplate(agent, type); if (template == null) { throw new TemplateMissingException($"The template for {agent} and type {type} is missing"); } if (!template.Enabled) { return new NotificationMessageContent { Disabled = true }; } if (model.UserId.IsNullOrEmpty()) { if (model.RequestType == RequestType.Movie) { model.UserId = MovieRequest.RequestedUserId; } if (model.RequestType == RequestType.Album) { model.UserId = AlbumRequest.RequestedUserId; } if (model.RequestType == RequestType.TvShow) { model.UserId = TvRequest.RequestedUserId; } } var parsed = Parse(model, template, agent); 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); } protected UserNotificationPreferences GetUserPreference(string userId, NotificationAgent agent) { return UserNotificationPreferences.GetAll() .FirstOrDefault(x => x.Agent == agent && x.UserId == userId); } protected async Task> GetAdminUsers() { IEnumerable recipients = await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin); return recipients; } protected async Task> GetPrivilegedUsers() { IEnumerable recipients = await GetAdminUsers(); recipients = recipients.Concat(await _userManager.GetUsersInRoleAsync(OmbiRoles.PowerUser)); return recipients; } private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template, NotificationAgent agent) { var resolver = new NotificationMessageResolver(); var curlys = new NotificationMessageCurlys(); var preference = GetUserPreference(model.UserId, agent); if (model.RequestType == RequestType.Movie) { _log.LogDebug("Notification options: {@model}, Req: {@MovieRequest}, Settings: {@Customization}", model, MovieRequest, Customization); curlys.Setup(model, MovieRequest, Customization, preference); } else if (model.RequestType == RequestType.TvShow) { _log.LogDebug("Notification options: {@model}, Req: {@TvRequest}, Settings: {@Customization}", model, TvRequest, Customization); curlys.Setup(model, TvRequest, Customization, preference); } else if (model.RequestType == RequestType.Album) { _log.LogDebug("Notification options: {@model}, Req: {@AlbumRequest}, Settings: {@Customization}", model, AlbumRequest, Customization); curlys.Setup(model, AlbumRequest, Customization, preference); } var parsed = resolver.ParseMessage(template, curlys); return parsed; } protected abstract bool ValidateConfiguration(T settings); protected abstract Task NewRequest(NotificationOptions model, T settings); protected abstract Task NewIssue(NotificationOptions model, T settings); protected abstract Task IssueComment(NotificationOptions model, T settings); protected abstract Task IssueResolved(NotificationOptions model, T settings); protected abstract Task AddedToRequestQueue(NotificationOptions model, T settings); protected abstract Task RequestDeclined(NotificationOptions model, T settings); protected abstract Task RequestApproved(NotificationOptions model, T settings); protected abstract Task AvailableRequest(NotificationOptions model, T settings); protected abstract Task PartiallyAvailable(NotificationOptions model, T settings); protected abstract Task Send(NotificationMessage model, T settings); protected abstract Task Test(NotificationOptions model, T settings); } }