mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-11 07:46:05 -07:00
#1462 #865 Had to refactor how we use notificaitons. So we now have more notification fields about the request
This commit is contained in:
parent
b69b322bd5
commit
b52a57b117
21 changed files with 256 additions and 112 deletions
|
@ -1,7 +1,6 @@
|
||||||
using Ombi.Core.Claims;
|
using Ombi.Core.Claims;
|
||||||
using Ombi.Core.Rule;
|
using Ombi.Core.Rule;
|
||||||
using Ombi.Core.Rules;
|
using Ombi.Core.Rules;
|
||||||
using Ombi.Store.Entities;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -29,35 +28,15 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
return User.IsInRole(roleName);
|
return User.IsInRole(roleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool ShouldSendNotification(RequestType type)
|
protected bool ShouldSendNotification(BaseRequest req)
|
||||||
{
|
{
|
||||||
var sendNotification = !ShouldAutoApprove(type); /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/
|
var sendNotification = !req.Approved; /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/
|
||||||
|
|
||||||
if (HasRole(OmbiClaims.Admin))
|
if (HasRole(OmbiClaims.Admin))
|
||||||
sendNotification = false; // Don't bother sending a notification if the user is an admin
|
sendNotification = false; // Don't bother sending a notification if the user is an admin
|
||||||
return sendNotification;
|
return sendNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShouldAutoApprove(RequestType requestType)
|
|
||||||
{
|
|
||||||
var admin = HasRole(OmbiClaims.Admin);
|
|
||||||
// if the user is an admin, they go ahead and allow auto-approval
|
|
||||||
if (admin) return true;
|
|
||||||
|
|
||||||
// check by request type if the category requires approval or not
|
|
||||||
switch (requestType)
|
|
||||||
{
|
|
||||||
case RequestType.Movie:
|
|
||||||
return HasRole(OmbiClaims.AutoApproveMovie);
|
|
||||||
|
|
||||||
case RequestType.TvShow:
|
|
||||||
return HasRole(OmbiClaims.AutoApproveTv);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
|
public async Task<IEnumerable<RuleResult>> RunRequestRules(BaseRequest model)
|
||||||
{
|
{
|
||||||
var ruleResults = await Rules.StartRequestRules(model);
|
var ruleResults = await Rules.StartRequestRules(model);
|
||||||
|
|
|
@ -10,9 +10,6 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
|
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
|
||||||
|
|
||||||
bool ShouldAutoApprove(RequestType requestType);
|
|
||||||
|
|
||||||
|
|
||||||
Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
|
Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search);
|
||||||
|
|
||||||
Task RemoveMovieRequest(int requestId);
|
Task RemoveMovieRequest(int requestId);
|
||||||
|
|
|
@ -142,6 +142,8 @@ namespace Ombi.Core.Engine
|
||||||
$"{fullMovieName} has been successfully added!");
|
$"{fullMovieName} has been successfully added!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
|
public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
|
||||||
{
|
{
|
||||||
var allRequests = await MovieRepository.Get().Skip(position).Take(count).ToListAsync();
|
var allRequests = await MovieRepository.Get().Skip(position).Take(count).ToListAsync();
|
||||||
|
@ -191,7 +193,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
await MovieRepository.Add(model);
|
await MovieRepository.Add(model);
|
||||||
|
|
||||||
if (ShouldSendNotification(RequestType.Movie))
|
if (ShouldSendNotification(model))
|
||||||
{
|
{
|
||||||
NotificationHelper.NewRequest(model);
|
NotificationHelper.NewRequest(model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,9 +293,9 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
private Task<RequestEngineResult> AfterRequest(ChildRequests model)
|
private Task<RequestEngineResult> AfterRequest(ChildRequests model)
|
||||||
{
|
{
|
||||||
if (ShouldSendNotification(RequestType.TvShow))
|
if (ShouldSendNotification(model))
|
||||||
{
|
{
|
||||||
//NotificationHelper.NewRequest(model.ParentRequest);
|
NotificationHelper.NewRequest(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(model.Approved)
|
if(model.Approved)
|
||||||
|
|
|
@ -6,5 +6,6 @@ namespace Ombi.Core
|
||||||
public interface INotificationHelper
|
public interface INotificationHelper
|
||||||
{
|
{
|
||||||
void NewRequest(FullBaseRequest model);
|
void NewRequest(FullBaseRequest model);
|
||||||
|
void NewRequest(ChildRequests model);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,14 +21,22 @@ namespace Ombi.Core
|
||||||
{
|
{
|
||||||
var notificationModel = new NotificationOptions
|
var notificationModel = new NotificationOptions
|
||||||
{
|
{
|
||||||
Title = model.Title,
|
RequestId = model.Id,
|
||||||
RequestedUser = model.RequestedUser.Username,
|
|
||||||
DateTime = DateTime.Now,
|
DateTime = DateTime.Now,
|
||||||
NotificationType = NotificationType.NewRequest,
|
NotificationType = NotificationType.NewRequest,
|
||||||
RequestType = model.RequestType,
|
RequestType = model.RequestType
|
||||||
ImgSrc = model.RequestType == RequestType.Movie
|
};
|
||||||
? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}"
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
: model.PosterPath
|
|
||||||
|
}
|
||||||
|
public void NewRequest(ChildRequests model)
|
||||||
|
{
|
||||||
|
var notificationModel = new NotificationOptions
|
||||||
|
{
|
||||||
|
RequestId = model.Id,
|
||||||
|
DateTime = DateTime.Now,
|
||||||
|
NotificationType = NotificationType.NewRequest,
|
||||||
|
RequestType = model.RequestType
|
||||||
};
|
};
|
||||||
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
BackgroundJob.Enqueue(() => NotificationService.Publish(notificationModel));
|
||||||
|
|
||||||
|
|
|
@ -6,22 +6,34 @@ namespace Ombi.Notifications.Templates
|
||||||
{
|
{
|
||||||
public class EmailBasicTemplate : IEmailBasicTemplate
|
public class EmailBasicTemplate : IEmailBasicTemplate
|
||||||
{
|
{
|
||||||
public string TemplateLocation => Path.Combine(Directory.GetCurrentDirectory(), "Templates","BasicTemplate.html");
|
public string TemplateLocation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
return Path.Combine(Directory.GetCurrentDirectory(), "bin","Debug", "netcoreapp1.1","Templates", "BasicTemplate.html");
|
||||||
|
#else
|
||||||
|
return Path.Combine(Directory.GetCurrentDirectory(), "Templates","BasicTemplate.html");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private const string SubjectKey = "{@SUBJECT}";
|
private const string SubjectKey = "{@SUBJECT}";
|
||||||
private const string BodyKey = "{@BODY}";
|
private const string BodyKey = "{@BODY}";
|
||||||
private const string ImgSrc = "{@IMGSRC}";
|
private const string ImgSrc = "{@IMGSRC}";
|
||||||
private const string DateKey = "{@DATENOW}";
|
private const string DateKey = "{@DATENOW}";
|
||||||
|
|
||||||
public string LoadTemplate(string subject, string body, string imgSrc)
|
public string LoadTemplate(string subject, string body, string img)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
|
var sb = new StringBuilder(File.ReadAllText(TemplateLocation));
|
||||||
sb.Replace(SubjectKey, subject);
|
sb.Replace(SubjectKey, subject);
|
||||||
sb.Replace(BodyKey, body);
|
sb.Replace(BodyKey, body);
|
||||||
sb.Replace(ImgSrc, imgSrc);
|
|
||||||
sb.Replace(DateKey, DateTime.Now.ToString("f"));
|
sb.Replace(DateKey, DateTime.Now.ToString("f"));
|
||||||
|
sb.Replace(ImgSrc, img);
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
public interface IEmailBasicTemplate
|
public interface IEmailBasicTemplate
|
||||||
{
|
{
|
||||||
string LoadTemplate(string subject, string body, string imgSrc);
|
string LoadTemplate(string subject, string body, string img);
|
||||||
string TemplateLocation { get; }
|
string TemplateLocation { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,4 +4,10 @@
|
||||||
<TargetFramework>netstandard1.4</TargetFramework>
|
<TargetFramework>netstandard1.4</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Templates\BasicTemplate.html">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
|
@ -172,7 +172,7 @@
|
||||||
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
|
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-top: 10px; padding-bottom: 10px; font-size: 12px; color: #999999; text-align: center;" valign="top" align="center">
|
||||||
Powered by <a href="https://github.com/tidusjar/Ombi" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Ombi</a>
|
Powered by <a href="https://github.com/tidusjar/Ombi" style="color: #999999; font-size: 12px; text-align: center; text-decoration: underline;">Ombi</a> {@DATENOW}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -9,13 +9,15 @@ using Ombi.Helpers;
|
||||||
using Ombi.Notifications.Interfaces;
|
using Ombi.Notifications.Interfaces;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
using Ombi.Settings.Settings.Models.Notifications;
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
namespace Ombi.Notifications.Agents
|
namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
public class DiscordNotification : BaseNotification<DiscordNotificationSettings>, IDiscordNotification
|
public class DiscordNotification : BaseNotification<DiscordNotificationSettings>, IDiscordNotification
|
||||||
{
|
{
|
||||||
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn, ILogger<DiscordNotification> log, INotificationTemplatesRepository r) : base(sn, r)
|
public DiscordNotification(IDiscordApi api, ISettingsService<DiscordNotificationSettings> sn, ILogger<DiscordNotification> log, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(sn, r, m, t)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Logger = log;
|
Logger = log;
|
||||||
|
@ -50,67 +52,89 @@ namespace Ombi.Notifications.Agents
|
||||||
|
|
||||||
protected override async Task NewRequest(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task NewRequest(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.NewRequest);
|
var parsed = await LoadTemplate(NotificationAgent.Discord, NotificationType.NewRequest, model);
|
||||||
|
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = template.Message,
|
Message = parsed.Message,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task Issue(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task Issue(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.Issue);
|
var parsed = await LoadTemplate(NotificationAgent.Discord, NotificationType.Issue, model);
|
||||||
|
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = template.Message,
|
Message = parsed.Message,
|
||||||
};
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task AddedToRequestQueue(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task AddedToRequestQueue(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var message = $"Hello! The user '{model.RequestedUser}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
var user = string.Empty;
|
||||||
|
var title = string.Empty;
|
||||||
|
var image = string.Empty;
|
||||||
|
if (model.RequestType == RequestType.Movie)
|
||||||
|
{
|
||||||
|
user = MovieRequest.RequestedUser.UserAlias;
|
||||||
|
title = MovieRequest.Title;
|
||||||
|
image = MovieRequest.PosterPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = TvRequest.RequestedUser.UserAlias;
|
||||||
|
title = TvRequest.ParentRequest.Title;
|
||||||
|
image = TvRequest.ParentRequest.PosterPath;
|
||||||
|
}
|
||||||
|
var message = $"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying";
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = message
|
Message = message
|
||||||
};
|
};
|
||||||
notification.Other.Add("image", model.ImgSrc);
|
notification.Other.Add("image", image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task RequestDeclined(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task RequestDeclined(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestDeclined);
|
var parsed = await LoadTemplate(NotificationAgent.Discord, NotificationType.RequestDeclined, model);
|
||||||
|
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = template.Message,
|
Message = parsed.Message,
|
||||||
};
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task RequestApproved(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task RequestApproved(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestApproved);
|
var parsed = await LoadTemplate(NotificationAgent.Discord, NotificationType.RequestApproved, model);
|
||||||
|
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = template.Message,
|
Message = parsed.Message,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task AvailableRequest(NotificationOptions model, DiscordNotificationSettings settings)
|
protected override async Task AvailableRequest(NotificationOptions model, DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, NotificationType.RequestAvailable);
|
var parsed = await LoadTemplate(NotificationAgent.Discord, NotificationType.RequestAvailable, model);
|
||||||
|
|
||||||
var notification = new NotificationMessage
|
var notification = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = template.Message,
|
Message = parsed.Message,
|
||||||
};
|
};
|
||||||
|
notification.Other.Add("image", parsed.Image);
|
||||||
await Send(notification, settings);
|
await Send(notification, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +162,7 @@ namespace Ombi.Notifications.Agents
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await Api.SendMessage(discordBody, settings.WebookId, settings.Token);
|
await Api.SendMessage(discordBody, settings.WebookId, settings.Token);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -8,13 +8,15 @@ using Ombi.Notifications.Interfaces;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
using Ombi.Notifications.Templates;
|
using Ombi.Notifications.Templates;
|
||||||
using Ombi.Settings.Settings.Models.Notifications;
|
using Ombi.Settings.Settings.Models.Notifications;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
namespace Ombi.Notifications.Agents
|
namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
|
public class EmailNotification : BaseNotification<EmailNotificationSettings>, IEmailNotification
|
||||||
{
|
{
|
||||||
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r) : base(settings, r)
|
public EmailNotification(ISettingsService<EmailNotificationSettings> settings, INotificationTemplatesRepository r, IMovieRequestRepository m, ITvRequestRepository t) : base(settings, r, m, t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,23 +42,14 @@ namespace Ombi.Notifications.Agents
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<NotificationMessage> LoadTemplate(NotificationType type, NotificationOptions model, EmailNotificationSettings settings)
|
private async Task<NotificationMessage> LoadTemplate(NotificationType type, NotificationOptions model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var template = await TemplateRepository.GetTemplate(NotificationAgent.Email, type);
|
var parsed = await LoadTemplate(NotificationAgent.Email, type, model);
|
||||||
if (!template.Enabled)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Need to do the parsing
|
|
||||||
var resolver = new NotificationMessageResolver();
|
|
||||||
var parsed = resolver.ParseMessage(template, new NotificationMessageCurlys(model.RequestedUser, model.Title, DateTime.Now.ToString("D"),
|
|
||||||
model.NotificationType.ToString(), null));
|
|
||||||
|
|
||||||
|
|
||||||
var email = new EmailBasicTemplate();
|
var email = new EmailBasicTemplate();
|
||||||
var html = email.LoadTemplate(parsed.Subject, parsed.Message, model.ImgSrc);
|
var html = email.LoadTemplate(parsed.Subject, parsed.Message,parsed.Image);
|
||||||
|
|
||||||
|
|
||||||
var message = new NotificationMessage
|
var message = new NotificationMessage
|
||||||
{
|
{
|
||||||
|
@ -67,8 +60,8 @@ namespace Ombi.Notifications.Agents
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override async Task NewRequest(NotificationOptions model, EmailNotificationSettings settings)
|
protected override async Task NewRequest(NotificationOptions model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
|
@ -77,8 +70,8 @@ namespace Ombi.Notifications.Agents
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has requested the {model.RequestType} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime:f}");
|
//message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has requested the {model.RequestType} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime:f}");
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +84,7 @@ namespace Ombi.Notifications.Agents
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has reported a new issue {model.Body} for the title {model.Title}!");
|
//message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has reported a new issue {model.Body} for the title {model.Title}!");
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
}
|
}
|
||||||
|
@ -99,10 +92,24 @@ namespace Ombi.Notifications.Agents
|
||||||
protected override async Task AddedToRequestQueue(NotificationOptions model, EmailNotificationSettings settings)
|
protected override async Task AddedToRequestQueue(NotificationOptions model, EmailNotificationSettings settings)
|
||||||
{
|
{
|
||||||
var email = new EmailBasicTemplate();
|
var email = new EmailBasicTemplate();
|
||||||
|
var user = string.Empty;
|
||||||
|
var title = string.Empty;
|
||||||
|
var img = string.Empty;
|
||||||
|
if (model.RequestType == RequestType.Movie)
|
||||||
|
{
|
||||||
|
user = MovieRequest.RequestedUser.UserAlias;
|
||||||
|
title = MovieRequest.Title;
|
||||||
|
img = MovieRequest.PosterPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = TvRequest.RequestedUser.UserAlias;
|
||||||
|
title = TvRequest.ParentRequest.Title;
|
||||||
|
img = TvRequest.ParentRequest.PosterPath;
|
||||||
|
}
|
||||||
var html = email.LoadTemplate(
|
var html = email.LoadTemplate(
|
||||||
"Ombi: A request could not be added.",
|
"Ombi: A request could not be added.",
|
||||||
$"Hello! The user '{model.RequestedUser}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying",
|
$"Hello! The user '{user}' has requested {title} but it could not be added. This has been added into the requests queue and will keep retrying", img);
|
||||||
model.ImgSrc);
|
|
||||||
|
|
||||||
var message = new NotificationMessage
|
var message = new NotificationMessage
|
||||||
{
|
{
|
||||||
|
@ -111,7 +118,7 @@ namespace Ombi.Notifications.Agents
|
||||||
To = settings.AdminEmail,
|
To = settings.AdminEmail,
|
||||||
};
|
};
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying");
|
//message.Other.Add("PlainTextBody", $"Hello! The user '{model.RequestedUser}' has requested {model.Title} but it could not be added. This has been added into the requests queue and will keep retrying");
|
||||||
|
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
|
@ -125,7 +132,7 @@ namespace Ombi.Notifications.Agents
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been declined, Sorry!");
|
//message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been declined, Sorry!");
|
||||||
|
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
|
@ -139,7 +146,7 @@ namespace Ombi.Notifications.Agents
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been approved!");
|
//message.Other.Add("PlainTextBody", $"Hello! Your request for {model.Title} has been approved!");
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +159,7 @@ namespace Ombi.Notifications.Agents
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Other.Add("PlainTextBody", $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)");
|
//message.Other.Add("PlainTextBody", $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)");
|
||||||
|
|
||||||
await Send(message, settings);
|
await Send(message, settings);
|
||||||
}
|
}
|
||||||
|
@ -164,7 +171,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var body = new BodyBuilder
|
var body = new BodyBuilder
|
||||||
{
|
{
|
||||||
HtmlBody = model.Message,
|
HtmlBody = model.Message,
|
||||||
TextBody = model.Other["PlainTextBody"]
|
//TextBody = model.Other["PlainTextBody"]
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = new MimeMessage
|
var message = new MimeMessage
|
||||||
|
@ -204,8 +211,7 @@ namespace Ombi.Notifications.Agents
|
||||||
var email = new EmailBasicTemplate();
|
var email = new EmailBasicTemplate();
|
||||||
var html = email.LoadTemplate(
|
var html = email.LoadTemplate(
|
||||||
"Test Message",
|
"Test Message",
|
||||||
"This is just a test! Success!",
|
"This is just a test! Success!", "");
|
||||||
model.ImgSrc);
|
|
||||||
var message = new NotificationMessage
|
var message = new NotificationMessage
|
||||||
{
|
{
|
||||||
Message = html,
|
Message = html,
|
||||||
|
|
|
@ -1,22 +1,34 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Settings;
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Notifications.Models;
|
using Ombi.Notifications.Models;
|
||||||
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using Ombi.Store.Repository.Requests;
|
||||||
|
|
||||||
namespace Ombi.Notifications.Interfaces
|
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)
|
protected BaseNotification(ISettingsService<T> settings, INotificationTemplatesRepository templateRepo, IMovieRequestRepository movie, ITvRequestRepository tv)
|
||||||
{
|
{
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
TemplateRepository = templateRepo;
|
TemplateRepository = templateRepo;
|
||||||
|
MovieRepository = movie;
|
||||||
|
TvRepository = tv;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ISettingsService<T> Settings { get; }
|
protected ISettingsService<T> Settings { get; }
|
||||||
protected INotificationTemplatesRepository TemplateRepository { get; }
|
protected INotificationTemplatesRepository TemplateRepository { get; }
|
||||||
|
protected IMovieRequestRepository MovieRepository { get; }
|
||||||
|
protected ITvRequestRepository TvRepository { get; }
|
||||||
|
|
||||||
|
protected ChildRequests TvRequest { get; set; }
|
||||||
|
protected MovieRequests MovieRequest { get; set; }
|
||||||
|
|
||||||
public abstract string NotificationName { get; }
|
public abstract string NotificationName { get; }
|
||||||
|
|
||||||
public async Task NotifyAsync(NotificationOptions model)
|
public async Task NotifyAsync(NotificationOptions model)
|
||||||
|
@ -30,11 +42,18 @@ namespace Ombi.Notifications.Interfaces
|
||||||
if (settings == null) await NotifyAsync(model);
|
if (settings == null) await NotifyAsync(model);
|
||||||
|
|
||||||
var notificationSettings = (T)settings;
|
var notificationSettings = (T)settings;
|
||||||
|
|
||||||
if (!ValidateConfiguration(notificationSettings))
|
if (!ValidateConfiguration(notificationSettings))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is this a test?
|
||||||
|
// The request id for tests is -1
|
||||||
|
if (model.RequestId > 0)
|
||||||
|
{
|
||||||
|
await LoadRequest(model.RequestId, model.RequestType);
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (model.NotificationType)
|
switch (model.NotificationType)
|
||||||
|
@ -73,12 +92,54 @@ namespace Ombi.Notifications.Interfaces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual async Task LoadRequest(int requestId, RequestType type)
|
||||||
|
{
|
||||||
|
if (type == RequestType.Movie)
|
||||||
|
{
|
||||||
|
MovieRequest = await MovieRepository.Get().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
|
MovieRequest.PosterPath = $"https://image.tmdb.org/t/p/w300/{MovieRequest.PosterPath}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TvRequest = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private T GetConfiguration()
|
private T GetConfiguration()
|
||||||
{
|
{
|
||||||
var settings = Settings.GetSettings();
|
var settings = Settings.GetSettings();
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual async Task<NotificationMessageContent> LoadTemplate(NotificationAgent agent, NotificationType type, NotificationOptions model)
|
||||||
|
{
|
||||||
|
var template = await TemplateRepository.GetTemplate(agent, type);
|
||||||
|
if (!template.Enabled)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var parsed = Parse(model, template);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotificationMessageContent Parse(NotificationOptions model, NotificationTemplates template)
|
||||||
|
{
|
||||||
|
var resolver = new NotificationMessageResolver();
|
||||||
|
var curlys = new NotificationMessageCurlys();
|
||||||
|
if (model.RequestType == RequestType.Movie)
|
||||||
|
{
|
||||||
|
curlys.Setup(MovieRequest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curlys.Setup(TvRequest);
|
||||||
|
}
|
||||||
|
var parsed = resolver.ParseMessage(template, curlys);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected abstract bool ValidateConfiguration(T settings);
|
protected abstract bool ValidateConfiguration(T settings);
|
||||||
protected abstract Task NewRequest(NotificationOptions model, T settings);
|
protected abstract Task NewRequest(NotificationOptions model, T settings);
|
||||||
|
|
|
@ -7,13 +7,9 @@ namespace Ombi.Notifications.Models
|
||||||
{
|
{
|
||||||
public class NotificationOptions
|
public class NotificationOptions
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public int RequestId { get; set; }
|
||||||
public string Body { get; set; }
|
|
||||||
public DateTime DateTime { get; set; } = DateTime.Now;
|
public DateTime DateTime { get; set; } = DateTime.Now;
|
||||||
public NotificationType NotificationType { get; set; }
|
public NotificationType NotificationType { get; set; }
|
||||||
public string RequestedUser { get; set; }
|
|
||||||
public string UserEmail { get; set; }
|
|
||||||
public RequestType RequestType { get; set; }
|
public RequestType RequestType { get; set; }
|
||||||
public string ImgSrc { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
|
using Ombi.Store.Entities.Requests;
|
||||||
|
|
||||||
namespace Ombi.Notifications
|
namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
|
@ -8,24 +10,49 @@ namespace Ombi.Notifications
|
||||||
{
|
{
|
||||||
public string Subject { get; set; }
|
public string Subject { get; set; }
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
public string Image { get; set; }
|
||||||
}
|
}
|
||||||
public class NotificationMessageCurlys
|
public class NotificationMessageCurlys
|
||||||
{
|
{
|
||||||
public NotificationMessageCurlys(string requestedUser, string title, string requestedDateTime, string type, string issue)
|
|
||||||
|
public void Setup(FullBaseRequest req)
|
||||||
{
|
{
|
||||||
RequestedUser = requestedUser;
|
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
|
||||||
Title = title;
|
? req.RequestedUser.Username
|
||||||
RequestedDate = requestedDateTime;
|
: req.RequestedUser.Alias;
|
||||||
Type = type;
|
Title = req.Title;
|
||||||
Issue = issue;
|
RequestedDate = req.RequestedDate.ToString("D");
|
||||||
|
Type = req.RequestType.ToString();
|
||||||
|
Overview = req.Overview;
|
||||||
|
Year = req.ReleaseDate.Year.ToString();
|
||||||
|
PosterImage = req.PosterPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Setup(ChildRequests req)
|
||||||
|
{
|
||||||
|
RequestedUser = string.IsNullOrEmpty(req.RequestedUser.Alias)
|
||||||
|
? req.RequestedUser.Username
|
||||||
|
: req.RequestedUser.Alias;
|
||||||
|
Title = req.ParentRequest.Title;
|
||||||
|
RequestedDate = req.RequestedDate.ToString("D");
|
||||||
|
Type = req.RequestType.ToString();
|
||||||
|
Overview = req.ParentRequest.Overview;
|
||||||
|
Year = req.ParentRequest.ReleaseDate.Year.ToString();
|
||||||
|
PosterImage = req.ParentRequest.PosterPath;
|
||||||
|
// DO Episode and Season Lists
|
||||||
}
|
}
|
||||||
|
|
||||||
// User Defined
|
// User Defined
|
||||||
private string RequestedUser { get; }
|
public string RequestedUser { get; set; }
|
||||||
private string Title { get; }
|
public string Title { get; set; }
|
||||||
private string RequestedDate { get; }
|
public string RequestedDate { get; set; }
|
||||||
private string Type { get; }
|
public string Type { get; set; }
|
||||||
private string Issue { get; }
|
public string Issue { get; set; }
|
||||||
|
public string Overview { get; set; }
|
||||||
|
public string Year { get; set; }
|
||||||
|
public string EpisodesList { get; set; }
|
||||||
|
public string SeasonsList { get; set; }
|
||||||
|
public string PosterImage { get; set; }
|
||||||
|
|
||||||
// System Defined
|
// System Defined
|
||||||
private string LongDate => DateTime.Now.ToString("D");
|
private string LongDate => DateTime.Now.ToString("D");
|
||||||
|
@ -44,6 +71,11 @@ namespace Ombi.Notifications
|
||||||
{nameof(ShortDate),ShortDate},
|
{nameof(ShortDate),ShortDate},
|
||||||
{nameof(LongTime),LongTime},
|
{nameof(LongTime),LongTime},
|
||||||
{nameof(ShortTime),ShortTime},
|
{nameof(ShortTime),ShortTime},
|
||||||
|
{nameof(Overview),Overview},
|
||||||
|
{nameof(Year),Year},
|
||||||
|
{nameof(EpisodesList),EpisodesList},
|
||||||
|
{nameof(SeasonsList),SeasonsList},
|
||||||
|
{nameof(PosterImage),PosterImage},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +98,9 @@ namespace Ombi.Notifications
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public NotificationMessageContent ParseMessage(NotificationTemplates notification, NotificationMessageCurlys c)
|
public NotificationMessageContent ParseMessage(NotificationTemplates notification, NotificationMessageCurlys c)
|
||||||
{
|
{
|
||||||
return Resolve(notification.Message, notification.Subject, c.Curlys);
|
var content = Resolve(notification.Message, notification.Subject, c.Curlys);
|
||||||
|
content.Image = c.PosterImage;
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,8 +118,7 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
body = ReplaceFields(bodyFields, parameters, body);
|
body = ReplaceFields(bodyFields, parameters, body);
|
||||||
subject = ReplaceFields(subjectFields, parameters, subject);
|
subject = ReplaceFields(subjectFields, parameters, subject);
|
||||||
|
return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty};
|
||||||
return new NotificationMessageContent { Message = body ?? string.Empty, Subject = subject ?? string.Empty };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -52,8 +52,13 @@ namespace Ombi.Notifications
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task Publish(NotificationOptions model)
|
public async Task Publish(NotificationOptions model)
|
||||||
{
|
{
|
||||||
var notificationTasks = NotificationAgents.Select(notification => NotifyAsync(notification, model));
|
//var notificationTasks = NotificationAgents.Select(notification => NotifyAsync(notification, model));
|
||||||
|
var notificationTasks = new List<Task>();
|
||||||
|
|
||||||
|
foreach (var agent in NotificationAgents)
|
||||||
|
{
|
||||||
|
notificationTasks.Add(NotifyAsync(agent,model));
|
||||||
|
}
|
||||||
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
await Task.WhenAll(notificationTasks).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +91,10 @@ namespace Ombi.Notifications
|
||||||
|
|
||||||
private async Task NotifyAsync(INotification notification, NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings)
|
private async Task NotifyAsync(INotification notification, NotificationOptions model, Ombi.Settings.Settings.Models.Settings settings)
|
||||||
{
|
{
|
||||||
|
if (model.RequestId == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("RequestId is not set");
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await notification.NotifyAsync(model, settings).ConfigureAwait(false);
|
await notification.NotifyAsync(model, settings).ConfigureAwait(false);
|
||||||
|
|
|
@ -44,6 +44,9 @@ namespace Ombi.Store.Entities
|
||||||
public byte[] Salt { get; set; }
|
public byte[] Salt { get; set; }
|
||||||
public UserType UserType { get; set; }
|
public UserType UserType { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string UserAlias => string.IsNullOrEmpty(Alias) ? Username : Alias;
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public List<Claim> Claims {
|
public List<Claim> Claims {
|
||||||
get => JsonConvert.DeserializeObject<List<Claim>>(ClaimsSerialized, new ClaimConverter());
|
get => JsonConvert.DeserializeObject<List<Claim>>(ClaimsSerialized, new ClaimConverter());
|
||||||
|
|
|
@ -49,7 +49,9 @@ namespace Ombi.Store.Repository
|
||||||
|
|
||||||
public GlobalSettings Get(string pageName)
|
public GlobalSettings Get(string pageName)
|
||||||
{
|
{
|
||||||
return Db.Settings.FirstOrDefault(x => x.SettingsName == pageName);
|
var entity = Db.Settings.FirstOrDefault(x => x.SettingsName == pageName);
|
||||||
|
Db.Entry(entity).Reload();
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<GlobalSettings> GetAsync(string settingsName)
|
public async Task<GlobalSettings> GetAsync(string settingsName)
|
||||||
|
|
|
@ -15,6 +15,11 @@ export class NotificationTemplate {
|
||||||
{RequestedDate} : The Date the media was requested <br/>
|
{RequestedDate} : The Date the media was requested <br/>
|
||||||
{Title} : The title of the request e.g. Lion King <br/>
|
{Title} : The title of the request e.g. Lion King <br/>
|
||||||
{Type} : The request type e.g. Movie/Tv Show <br/>
|
{Type} : The request type e.g. Movie/Tv Show <br/>
|
||||||
|
{Overview} : Overview of the requested item <br/>
|
||||||
|
{Year} : The release year of the request<br/>
|
||||||
|
{EpisodesList} : A comma seperated list of Episodes requested<br/>
|
||||||
|
{SeasonsList} : A comma seperated list of seasons requested<br/>
|
||||||
|
{PosterImage} : The requested poster image link<br/>
|
||||||
{LongDate} : 15 June 2017 <br/>
|
{LongDate} : 15 June 2017 <br/>
|
||||||
{ShortDate} : 15/06/2017 <br/>
|
{ShortDate} : 15/06/2017 <br/>
|
||||||
{LongTime} : 16:02:34 <br/>
|
{LongTime} : 16:02:34 <br/>
|
||||||
|
|
|
@ -43,7 +43,8 @@ namespace Ombi.Controllers.External
|
||||||
public bool Discord([FromBody] DiscordNotificationSettings settings)
|
public bool Discord([FromBody] DiscordNotificationSettings settings)
|
||||||
{
|
{
|
||||||
settings.Enabled = true;
|
settings.Enabled = true;
|
||||||
BackgroundJob.Enqueue(() => Service.PublishTest(new NotificationOptions{NotificationType = NotificationType.Test}, settings, (DiscordNotification)DiscordNotification));
|
DiscordNotification.NotifyAsync(
|
||||||
|
new NotificationOptions {NotificationType = NotificationType.Test, RequestId = -1}, settings);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -60,10 +61,9 @@ namespace Ombi.Controllers.External
|
||||||
var notificationModel = new NotificationOptions
|
var notificationModel = new NotificationOptions
|
||||||
{
|
{
|
||||||
NotificationType = NotificationType.Test,
|
NotificationType = NotificationType.Test,
|
||||||
DateTime = DateTime.Now,
|
RequestId = -1
|
||||||
ImgSrc = "https://imgs.xkcd.com/comics/shouldnt_be_hard.png"
|
|
||||||
};
|
};
|
||||||
BackgroundJob.Enqueue(() => Service.PublishTest(notificationModel, settings, EmailNotification));
|
EmailNotification.NotifyAsync(notificationModel, settings);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/// <binding BeforeBuild='build' />
|
/// <binding BeforeBuild='build' />
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const gulp = require('gulp');
|
const gulp = require('gulp');
|
||||||
const run = require('gulp-run');
|
const run = require('gulp-run');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue