From 82a118b603fe1b9394be0cf2b253cc7987b358fe Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 18 Jan 2021 14:39:56 -0500 Subject: [PATCH] notification improvements --- .../Modules/Admin/UserProfile/Add.razor | 20 +--- .../Modules/Admin/UserProfile/View.razor | 20 +--- Oqtane.Server/Controllers/UserController.cs | 30 +----- .../Infrastructure/Jobs/NotificationJob.cs | 96 ++++++++++++------- .../Repository/NotificationRepository.cs | 4 +- Oqtane.Shared/Models/Notification.cs | 46 ++++++++- 6 files changed, 122 insertions(+), 94 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor index d32127268..dcc96ff43 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor @@ -48,26 +48,12 @@ private async Task Send() { - var notification = new Notification(); try { var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); if (user != null) - { - notification.SiteId = PageState.Site.SiteId; - notification.FromUserId = PageState.User.UserId; - notification.FromDisplayName = PageState.User.DisplayName; - notification.FromEmail = PageState.User.Email; - notification.ToUserId = user.UserId; - notification.ToDisplayName = user.DisplayName; - notification.ToEmail = user.Email; - notification.Subject = subject; - notification.Body = body; - notification.ParentId = null; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - notification.SendOn = DateTime.UtcNow; + { + var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null); notification = await NotificationService.AddNotificationAsync(notification); await logger.LogInformation("Notification Created {Notification}", notification); NavigationManager.NavigateTo(NavigateUrl()); @@ -79,7 +65,7 @@ } catch (Exception ex) { - await logger.LogError(ex, "Error Adding Notification {Notification} {Error}", notification, ex.Message); + await logger.LogError(ex, "Error Adding Notification {Error}", ex.Message); AddModuleMessage(Localizer["Error Adding Notification"], MessageType.Error); } } diff --git a/Oqtane.Client/Modules/Admin/UserProfile/View.razor b/Oqtane.Client/Modules/Admin/UserProfile/View.razor index fcd7340c0..ff9f39373 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/View.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/View.razor @@ -176,26 +176,12 @@ private async Task Send() { - var notification = new Notification(); try { var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); if (user != null) - { - notification.SiteId = PageState.Site.SiteId; - notification.FromUserId = PageState.User.UserId; - notification.FromDisplayName = PageState.User.DisplayName; - notification.FromEmail = PageState.User.Email; - notification.ToUserId = user.UserId; - notification.ToDisplayName = user.DisplayName; - notification.ToEmail = user.Email; - notification.Subject = subject; - notification.Body = body; - notification.ParentId = notificationid; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - notification.SendOn = DateTime.UtcNow; + { + var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, notificationid); notification = await NotificationService.AddNotificationAsync(notification); await logger.LogInformation("Notification Created {Notification}", notification); NavigationManager.NavigateTo(NavigateUrl()); @@ -207,7 +193,7 @@ } catch (Exception ex) { - await logger.LogError(ex, "Error Adding Notification {Notification} {Error}", notification, ex.Message); + await logger.LogError(ex, "Error Adding Notification {Error}", ex.Message); AddModuleMessage(Localizer["Error Adding Notification"], MessageType.Error); } } diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 5a97087af..9819994b6 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; @@ -146,20 +146,10 @@ private async Task CreateUser(User user) newUser = _users.AddUser(user); if (!verified) { - Notification notification = new Notification(); - notification.SiteId = user.SiteId; - notification.FromUserId = null; - notification.ToUserId = newUser.UserId; - notification.ToEmail = newUser.Email; - notification.Subject = "User Account Verification"; string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser); string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); - notification.Body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; - notification.ParentId = null; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - notification.SendOn = DateTime.UtcNow; + string body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!"; + var notification = new Notification(user.SiteId, null, newUser, "User Account Verification", body, null); _notifications.AddNotification(notification); } @@ -379,20 +369,10 @@ public async Task Forgot([FromBody] User user) IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username); if (identityuser != null) { - Notification notification = new Notification(); - notification.SiteId = user.SiteId; - notification.FromUserId = null; - notification.ToUserId = user.UserId; - notification.ToEmail = ""; - notification.Subject = "User Password Reset"; string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser); string url = HttpContext.Request.Scheme + "://" + _tenants.GetAlias().Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token); - notification.Body = "Dear " + user.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!"; - notification.ParentId = null; - notification.CreatedOn = DateTime.UtcNow; - notification.IsDelivered = false; - notification.DeliveredOn = null; - notification.SendOn = DateTime.UtcNow; + string body = "Dear " + user.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!"; + var notification = new Notification(user.SiteId, null, user, "User Password Reset", body, null); _notifications.AddNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", user.Username); } diff --git a/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs b/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs index 92d1d3366..7818d9d3b 100644 --- a/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs +++ b/Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs @@ -22,16 +22,18 @@ public NotificationJob(IServiceScopeFactory serviceScopeFactory) : base(serviceS IsEnabled = false; } + // job is executed for each tenant in installation public override string ExecuteJob(IServiceProvider provider) { string log = ""; // get services var siteRepository = provider.GetRequiredService(); + var userRepository = provider.GetRequiredService(); var settingRepository = provider.GetRequiredService(); var notificationRepository = provider.GetRequiredService(); - // iterate through sites for this tenant + // iterate through sites for current tenant List sites = siteRepository.GetSites().ToList(); foreach (Site site in sites) { @@ -59,49 +61,79 @@ public override string ExecuteJob(IServiceProvider provider) client.Credentials = new NetworkCredential(settings["SMTPUsername"], settings["SMTPPassword"]); } - // iterate through notifications + // iterate through undelivered notifications int sent = 0; List notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList(); foreach (Notification notification in notifications) { - MailMessage mailMessage = new MailMessage(); - mailMessage.From = new MailAddress(settings["SMTPSender"], site.Name); - mailMessage.Subject = notification.Subject; - if (notification.FromUserId != null) + // get sender and receiver information if not provided + if ((string.IsNullOrEmpty(notification.FromEmail) || string.IsNullOrEmpty(notification.FromDisplayName)) && notification.FromUserId != null) { - mailMessage.Body = "From: " + notification.FromDisplayName + "<" + notification.FromEmail + ">" + "\n"; + var user = userRepository.GetUser(notification.FromUserId.Value); + if (user != null) + { + notification.FromEmail = (string.IsNullOrEmpty(notification.FromEmail)) ? user.Email : notification.FromEmail; + notification.FromDisplayName = (string.IsNullOrEmpty(notification.FromDisplayName)) ? user.DisplayName : notification.FromDisplayName; + } } - else - { - mailMessage.Body = "From: " + site.Name + "\n"; - } - mailMessage.Body += "Sent: " + notification.CreatedOn + "\n"; - if (notification.ToUserId != null) + if ((string.IsNullOrEmpty(notification.ToEmail) || string.IsNullOrEmpty(notification.ToDisplayName)) && notification.ToUserId != null) { - mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName)); - mailMessage.Body += "To: " + notification.ToDisplayName + "<" + notification.ToEmail + ">" + "\n"; + var user = userRepository.GetUser(notification.ToUserId.Value); + if (user != null) + { + notification.ToEmail = (string.IsNullOrEmpty(notification.ToEmail)) ? user.Email : notification.ToEmail; + notification.ToDisplayName = (string.IsNullOrEmpty(notification.ToDisplayName)) ? user.DisplayName : notification.ToDisplayName; + } } - else - { - mailMessage.To.Add(new MailAddress(notification.ToEmail)); - mailMessage.Body += "To: " + notification.ToEmail + "\n"; - } - mailMessage.Body += "Subject: " + notification.Subject + "\n\n"; - mailMessage.Body += notification.Body; - - // send mail - try + + // validate recipient + if (string.IsNullOrEmpty(notification.ToEmail)) { - client.Send(mailMessage); - sent = sent++; - notification.IsDelivered = true; - notification.DeliveredOn = DateTime.UtcNow; + log += "Recipient Missing For NotificationId: " + notification.NotificationId + "
"; + notification.IsDeleted = true; notificationRepository.UpdateNotification(notification); } - catch (Exception ex) + else { - // error - log += ex.Message + "
"; + MailMessage mailMessage = new MailMessage(); + mailMessage.From = new MailAddress(settings["SMTPSender"], site.Name); + mailMessage.Subject = notification.Subject; + if (!string.IsNullOrEmpty(notification.FromEmail) && !string.IsNullOrEmpty(notification.FromDisplayName)) + { + mailMessage.Body = "From: " + notification.FromDisplayName + "<" + notification.FromEmail + ">" + "\n"; + } + else + { + mailMessage.Body = "From: " + site.Name + "\n"; + } + mailMessage.Body += "Sent: " + notification.CreatedOn + "\n"; + if (!string.IsNullOrEmpty(notification.ToEmail) && !string.IsNullOrEmpty(notification.ToDisplayName)) + { + mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName)); + mailMessage.Body += "To: " + notification.ToDisplayName + "<" + notification.ToEmail + ">" + "\n"; + } + else + { + mailMessage.To.Add(new MailAddress(notification.ToEmail)); + mailMessage.Body += "To: " + notification.ToEmail + "\n"; + } + mailMessage.Body += "Subject: " + notification.Subject + "\n\n"; + mailMessage.Body += notification.Body; + + // send mail + try + { + client.Send(mailMessage); + sent = sent++; + notification.IsDelivered = true; + notification.DeliveredOn = DateTime.UtcNow; + notificationRepository.UpdateNotification(notification); + } + catch (Exception ex) + { + // error + log += ex.Message + "
"; + } } } log += "Notifications Delivered: " + sent + "
"; diff --git a/Oqtane.Server/Repository/NotificationRepository.cs b/Oqtane.Server/Repository/NotificationRepository.cs index 43025c3a2..38ec8559c 100644 --- a/Oqtane.Server/Repository/NotificationRepository.cs +++ b/Oqtane.Server/Repository/NotificationRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Models; @@ -20,7 +20,7 @@ public IEnumerable GetNotifications(int siteId, int fromUserId, in { return _db.Notification .Where(item => item.SiteId == siteId) - .Where(item => item.IsDelivered == false) + .Where(item => item.IsDelivered == false && item.IsDeleted == false) .Where(item => item.SendOn == null || item.SendOn < System.DateTime.UtcNow) .ToList(); } diff --git a/Oqtane.Shared/Models/Notification.cs b/Oqtane.Shared/Models/Notification.cs index 7ccdbd9d4..6795c9544 100644 --- a/Oqtane.Shared/Models/Notification.cs +++ b/Oqtane.Shared/Models/Notification.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel.DataAnnotations.Schema; namespace Oqtane.Models @@ -23,6 +23,50 @@ public class Notification : IDeletable public DateTime? DeletedOn { get; set; } public bool IsDeleted { get; set; } public DateTime? SendOn { get; set; } + + public Notification() {} + + public Notification(int siteId, User from, User to, string subject, string body, int? parentId) + { + SiteId = siteId; + if (from != null) + { + FromUserId = from.UserId; + FromDisplayName = from.DisplayName; + FromEmail = from.Email; + } + if (to != null) + { + ToUserId = to.UserId; + ToDisplayName = to.DisplayName; + ToEmail = to.Email; + } + Subject = subject; + Body = body; + ParentId = parentId; + CreatedOn = DateTime.UtcNow; + IsDelivered = false; + DeliveredOn = null; + SendOn = DateTime.UtcNow; + } + + public Notification(int siteId, string fromDisplayName, string fromEmail, string toDisplayName, string toEmail, string subject, string body) + { + SiteId = siteId; + FromUserId = null; + FromDisplayName = fromDisplayName; + FromEmail = fromEmail; + ToUserId = null; + ToDisplayName = toDisplayName; + ToEmail = toEmail; + Subject = subject; + Body = body; + ParentId = null; + CreatedOn = DateTime.UtcNow; + IsDelivered = false; + DeliveredOn = null; + SendOn = DateTime.UtcNow; + } } }