From 3956a32b31e8cb408a6cc5b8e23bcc8cc2453361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 11:34:35 +0200 Subject: [PATCH 01/27] Adding new logic for 80% and 90% reminders --- .../Indexes/EmailQuotaIndex.cs | 2 + .../Migrations/EmailQuotaMigrations.cs | 14 ++++- .../Models/EmailQuota.cs | 1 + .../Services/EmailSenderQuotaService.cs | 56 ++++++++++++++----- .../Services/IQuotaService.cs | 14 ++++- .../Services/QuotaService.cs | 41 +++++++++++++- .../EmailTemplate__EmailQuotaWarning.cshtml | 4 ++ 7 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs index 9d862528..48ac00e0 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs @@ -8,6 +8,7 @@ public class EmailQuotaIndex : MapIndex { public int CurrentEmailQuotaCount { get; set; } public DateTime LastReminder { get; set; } + public int LastReminderPercentage { get; set; } } public class EmailQuotaIndexProvider : IndexProvider @@ -18,5 +19,6 @@ public override void Describe(DescribeContext context) => { CurrentEmailQuotaCount = emailQuota.CurrentEmailQuotaCount, LastReminder = emailQuota.LastReminder, + LastReminderPercentage = emailQuota.LastReminderPercentage, }); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs index 4420aaad..6460449a 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs @@ -11,8 +11,18 @@ public int Create() { SchemaBuilder.CreateMapIndexTable( table => table.Column(nameof(EmailQuotaIndex.CurrentEmailQuotaCount)) - .Column(nameof(EmailQuotaIndex.LastReminder))); + .Column(nameof(EmailQuotaIndex.LastReminder)) + .Column(nameof(EmailQuotaIndex.LastReminderPercentage))); - return 1; + return 2; + } + + public int UpdateFrom1() + { + SchemaBuilder.AlterTable(nameof(EmailQuotaIndex), table => table + .AddColumn(nameof(EmailQuotaIndex.LastReminderPercentage)) + ); + + return 2; } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs index 5061b563..6efd6c9c 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs @@ -6,4 +6,5 @@ public class EmailQuota { public int CurrentEmailQuotaCount { get; set; } public DateTime LastReminder { get; set; } + public int LastReminderPercentage { get; set; } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs index ae167fc8..01db94ab 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs @@ -4,8 +4,8 @@ using OrchardCore.Email; using OrchardCore.Environment.Shell; using OrchardCore.Environment.Shell.Scope; -using OrchardCore.Modules; -using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; @@ -16,7 +16,6 @@ public class EmailSenderQuotaService : ISmtpService private readonly ISmtpService _smtpService; private readonly IQuotaService _quotaService; private readonly IEmailQuotaEmailService _emailQuotaEmailService; - private readonly IClock _clock; private readonly ShellSettings _shellSettings; private readonly IEmailTemplateService _emailTemplateService; @@ -25,7 +24,6 @@ public EmailSenderQuotaService( IStringLocalizer stringLocalizer, IQuotaService quotaService, IEmailQuotaEmailService emailQuotaEmailService, - IClock clock, ShellSettings shellSettings, IEmailTemplateService emailTemplateService) { @@ -33,7 +31,6 @@ public EmailSenderQuotaService( T = stringLocalizer; _quotaService = quotaService; _emailQuotaEmailService = emailQuotaEmailService; - _clock = clock; _shellSettings = shellSettings; _emailTemplateService = emailTemplateService; } @@ -46,10 +43,11 @@ public async Task SendAsync(MailMessage message) } var isQuotaOverResult = await _quotaService.IsQuotaOverTheLimitAsync(); + await SendAlertEmailIfNecessaryAsync(isQuotaOverResult.EmailQuota); + + // Should send the email if the quota is not over the limit. if (isQuotaOverResult.IsOverQuota) { - await SendAlertEmailIfNecessaryAsync(isQuotaOverResult.EmailQuota); - return SmtpResult.Failed(T["The email quota for the site has been exceeded."]); } @@ -64,32 +62,60 @@ public async Task SendAsync(MailMessage message) private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) { - if (IsSameMonth(_clock.UtcNow, emailQuota.LastReminder)) return; + var currentUsagePercentage = _quotaService.CurrentUsagePercentage(emailQuota); + if (!_quotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; - emailQuota.LastReminder = _clock.UtcNow; - _quotaService.SaveQuota(emailQuota); + var siteOwnerEmails = (await _emailQuotaEmailService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); + if (currentUsagePercentage >= 100) + { + var emailMessage = new MailMessage + { + Subject = T["[Action Required] Your DotNest site has run over its e-mail quota"], + IsHtmlBody = true, + }; + SendQuotaEmail(siteOwnerEmails, emailMessage, "EmailQuota", currentUsagePercentage); + _quotaService.SaveQuotaReminder(emailQuota); + return; + } - var siteOwnerEmails = await _emailQuotaEmailService.CollectUserEmailsForExceedingQuotaAsync(); + SendQuotaEmailWithPercentage(siteOwnerEmails, currentUsagePercentage); + _quotaService.SaveQuotaReminder(emailQuota); + } + + private void SendQuotaEmailWithPercentage( + IEnumerable siteOwnerEmails, + int percentage) + { var emailMessage = new MailMessage { - Subject = T["[Action Required] Your DotNest site has run over its e-mail quota"], + Subject = T["[Warning] Your DotNest site has used {0}% of its e-mail quota", percentage], IsHtmlBody = true, }; + SendQuotaEmail(siteOwnerEmails, emailMessage, $"EmailQuotaWarning", percentage); + } + private void SendQuotaEmail( + IEnumerable siteOwnerEmails, + MailMessage emailMessage, + string emailTemplateName, + int percentage) + { foreach (var siteOwnerEmail in siteOwnerEmails) { ShellScope.AddDeferredTask(async _ => { emailMessage.To = siteOwnerEmail; - emailMessage.Body = await _emailTemplateService.RenderEmailTemplateAsync("EmailQuota", new + emailMessage.Body = await _emailTemplateService.RenderEmailTemplateAsync(emailTemplateName, new { HostName = _shellSettings.Name, + Percentage = percentage, }); + // ISmtpService must be used within this class otherwise it won't call the original ISmtpService + // implementation, but loop back to here. await _smtpService.SendAsync(emailMessage); }); } } - private static bool IsSameMonth(DateTime date1, DateTime date2) => - date1.Month == date2.Month && date1.Year == date2.Year; + } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs index 4e445c4b..4c312786 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs @@ -34,7 +34,17 @@ public interface IQuotaService void ResetQuota(EmailQuota emailQuota); /// - /// Saves the given quota. + /// Saves the given quota on reminder sent. /// - void SaveQuota(EmailQuota emailQuota); + void SaveQuotaReminder(EmailQuota emailQuota); + + /// + /// Returns if the reminder email should be sent. + /// + bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentage = null); + + /// + /// Returns the current quota usage percentage. + /// + int CurrentUsagePercentage(EmailQuota emailQuota); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs index 89537e64..0c77d5ed 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs @@ -5,6 +5,7 @@ using OrchardCore.Email; using OrchardCore.Environment.Shell.Configuration; using OrchardCore.Modules; +using System; using System.Threading.Tasks; using YesSql; @@ -67,15 +68,51 @@ public async Task GetCurrentQuotaAsync() public void IncreaseQuota(EmailQuota emailQuota) { emailQuota.CurrentEmailQuotaCount++; - SaveQuota(emailQuota); + _session.Save(emailQuota); } - public void SaveQuota(EmailQuota emailQuota) => + public void SaveQuotaReminder(EmailQuota emailQuota) + { + emailQuota.LastReminder = _clock.UtcNow; + emailQuota.LastReminderPercentage = CurrentUsagePercentage(emailQuota); _session.Save(emailQuota); + } + + public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentage = null) + { + currentPercentage ??= CurrentUsagePercentage(emailQuota); + if (currentPercentage < 80) + { + return false; + } + + var isSameMonth = IsSameMonth(_clock.UtcNow, emailQuota.LastReminder); + + if (!isSameMonth) + { + return true; + } + + switch (emailQuota.LastReminderPercentage) + { + case >= 80 when currentPercentage < 90: + case >= 90 when currentPercentage < 100: + case >= 100: + return false; + default: + return true; + } + } public void ResetQuota(EmailQuota emailQuota) { emailQuota.CurrentEmailQuotaCount = 0; _session.Save(emailQuota); } + + public int CurrentUsagePercentage(EmailQuota emailQuota) => + emailQuota.CurrentEmailQuotaCount / _emailQuotaOptions.EmailQuotaPerMonth * 100; + + private static bool IsSameMonth(DateTime date1, DateTime date2) => + date1.Month == date2.Month && date1.Year == date2.Year; } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml new file mode 100644 index 00000000..71e6887c --- /dev/null +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml @@ -0,0 +1,4 @@ +@{ + ViewLayout = "Layout__EmailTemplate"; +} +@T["

Hi

It seems that your {0} site sent out {1}% of available e-mail quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.

Thank you,
Your Admin Crew

", Model.HostName, Model.Percentage] From 2f185a4892ccdea5933ea4cc07e2aa383b1b7cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 12:37:12 +0200 Subject: [PATCH 02/27] Adding percentage warnings --- .../Filters/EmailQuotaErrorFilter.cs | 17 ++++++++++++++--- .../Services/EmailSenderQuotaService.cs | 2 +- .../Views/EmailQuotaError.cshtml | 9 ++++++++- .../Views/EmailTemplate__EmailQuota.cshtml | 2 +- .../EmailTemplate__EmailQuotaWarning.cshtml | 2 +- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs index 65aba68d..3122d2c9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs @@ -41,13 +41,24 @@ public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultE actionRouteArea == $"{nameof(OrchardCore)}.{nameof(OrchardCore.Admin)}" && actionRouteValue is nameof(AdminController.Index) && context.Result is ViewResult && - _quotaService.ShouldLimitEmails() && - (await _quotaService.IsQuotaOverTheLimitAsync()).IsOverQuota) + _quotaService.ShouldLimitEmails()) { var layout = await _layoutAccessor.GetLayoutAsync(); var contentZone = layout.Zones["Content"]; + var currentEmailQuota = await _quotaService.IsQuotaOverTheLimitAsync(); - await contentZone.AddAsync(await _shapeFactory.CreateAsync("EmailQuotaError"), "0"); + var roundedCurrentPercentage = _quotaService.CurrentUsagePercentage(currentEmailQuota.EmailQuota) / 10 * 10; + + if (roundedCurrentPercentage >= 80) + { + await contentZone.AddAsync( + await _shapeFactory.CreateAsync("EmailQuotaError", new + { + currentEmailQuota.IsOverQuota, + UsagePercentage = roundedCurrentPercentage, + }), + "0"); + } } await next(); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs index 01db94ab..6c3af878 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs @@ -78,7 +78,7 @@ private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) return; } - SendQuotaEmailWithPercentage(siteOwnerEmails, currentUsagePercentage); + SendQuotaEmailWithPercentage(siteOwnerEmails, currentUsagePercentage / 10 * 10); _quotaService.SaveQuotaReminder(emailQuota); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml index afdd2c06..5e2dc03a 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml @@ -1 +1,8 @@ -

@T["It seems that your site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."]

+@if (Model.IsOverQuota) +{ +

@T["It seems that your site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."]

+} +else +{ +

@T["It seems that your site sent out {0}% of e-mails from the available quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.", Model.UsagePercentage]

+} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml index fde5c9d0..77e87a07 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml @@ -1,4 +1,4 @@ @{ ViewLayout = "Layout__EmailTemplate"; } -@T["

Hi

It seems that your {0} site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank you,
Your Admin Crew

", Model.HostName] +@T["

Hi,

It seems that your {0} site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank you,
Your Admin Crew

", Model.HostName] diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml index 71e6887c..06e0179b 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml @@ -1,4 +1,4 @@ @{ ViewLayout = "Layout__EmailTemplate"; } -@T["

Hi

It seems that your {0} site sent out {1}% of available e-mail quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.

Thank you,
Your Admin Crew

", Model.HostName, Model.Percentage] +@T["

Hi,

It seems that your {0} site sent out {1}% of the available e-mail quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.

Thank you,
Your Admin Crew

", Model.HostName, Model.Percentage] From eef620afadd1fe09f22d28dfeab4f3be67717b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 12:37:23 +0200 Subject: [PATCH 03/27] Fixing calculations --- .../Services/QuotaService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs index 0c77d5ed..930d3f0f 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs @@ -111,7 +111,7 @@ public void ResetQuota(EmailQuota emailQuota) } public int CurrentUsagePercentage(EmailQuota emailQuota) => - emailQuota.CurrentEmailQuotaCount / _emailQuotaOptions.EmailQuotaPerMonth * 100; + Convert.ToInt32(Math.Round((double)emailQuota.CurrentEmailQuotaCount / _emailQuotaOptions.EmailQuotaPerMonth * 100, 0)); private static bool IsSameMonth(DateTime date1, DateTime date2) => date1.Month == date2.Month && date1.Year == date2.Year; From 6d1e19f7d81f6b7d088ca80a89f3e6eecf39e4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 16:59:12 +0200 Subject: [PATCH 04/27] Adding new functionality UI test --- .../TestCaseUITestContextExtensions.cs | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index da24a719..597cb9ab 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -2,7 +2,9 @@ using Lombiq.Tests.UI.Helpers; using Lombiq.Tests.UI.Services; using OpenQA.Selenium; +using Shouldly; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI.Extensions; @@ -11,7 +13,8 @@ public static class TestCaseUITestContextExtensions { private const string SuccessfulSubject = "Successful test message"; private const string UnSuccessfulSubject = "Unsuccessful test message"; - private const string DashboardWarning = + private const string WarningSubject = "[Warning] Your DotNest site has used"; + private const string DashboardExceededMessage = "//p[contains(@class,'alert-danger')][contains(.,'It seems that your site sent out more e-mails')]"; public static async Task TestEmailQuotaManagementBehaviorAsync( @@ -21,19 +24,37 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( { await context.SignInDirectlyAndGoToDashboardAsync(); - context.Missing(By.XPath(DashboardWarning)); + context.Missing(By.XPath(DashboardExceededMessage)); await context.GoToAdminRelativeUrlAsync("/Settings/email"); CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, 0); - await SendTestEmailAsync(context, SuccessfulSubject); - context.SuccessMessageExists(); - - CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, 1); - - await context.GoToDashboardAsync(); - context.CheckExistence(By.XPath(DashboardWarning), exists: moduleShouldInterfere); + var warningEmails = new List(); + for (int i = 0; i < maximumEmailQuota; i++) + { + await SendTestEmailAsync(context, SuccessfulSubject); + context.SuccessMessageExists(); + CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, i + 1); + var warningLevel = Convert.ToInt32((double)(i + 1) / maximumEmailQuota * 100) / 10 * 10; + if (warningLevel >= 100) + { + await context.GoToDashboardAsync(); + context.CheckExistence(By.XPath(DashboardExceededMessage), exists: moduleShouldInterfere); + } + else if (warningLevel >= 80) + { + await context.GoToDashboardAsync(); + context.CheckExistence( + By.XPath($"//p[contains(@class,'alert-warning')]" + + $"[contains(.,'It seems that your site sent out {warningLevel.ToTechnicalString()}% of e-mail')]"), + exists: moduleShouldInterfere); + if (!warningEmails.Contains(warningLevel)) + { + warningEmails.Add(warningLevel); + } + } + } await SendTestEmailAsync(context, UnSuccessfulSubject); await context.GoToSmtpWebUIAsync(); @@ -41,6 +62,16 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( context.CheckExistence( ByHelper.SmtpInboxRow("[Action Required] Your DotNest site has run over its e-mail quota"), exists: moduleShouldInterfere); + var warningMessageExists = context.CheckExistence( + ByHelper.SmtpInboxRow(WarningSubject), + exists: moduleShouldInterfere); + if (warningMessageExists) + { + (context.GetAll( + ByHelper.SmtpInboxRow(WarningSubject)).Count == warningEmails.Count) + .ShouldBeTrue(); + } + context.CheckExistence(ByHelper.SmtpInboxRow(UnSuccessfulSubject), exists: !moduleShouldInterfere); } From 7f2d54fcb85f493a35163d9b3867028d1acf4258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 17:08:50 +0200 Subject: [PATCH 05/27] Shouldn't do the rest if --- .../Extensions/TestCaseUITestContextExtensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index 597cb9ab..89855d05 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -37,6 +37,8 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( context.SuccessMessageExists(); CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, i + 1); var warningLevel = Convert.ToInt32((double)(i + 1) / maximumEmailQuota * 100) / 10 * 10; + if (!moduleShouldInterfere) continue; + if (warningLevel >= 100) { await context.GoToDashboardAsync(); From 2d5fba9a8dedd68a242e22997014ce7193babf17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Thu, 28 Sep 2023 17:42:53 +0200 Subject: [PATCH 06/27] Fixing code analyzer validations --- .../Services/EmailSenderQuotaService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs index 6c3af878..88403e4a 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs @@ -116,6 +116,4 @@ private void SendQuotaEmail( }); } } - - } From 2d0b9b99c00598c49a28cac85f11bbd4b8c7c467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 13:53:46 +0200 Subject: [PATCH 07/27] Breaking long lines --- .../Views/EmailQuotaError.cshtml | 11 +++++++++-- .../Views/EmailSettingsQuota.cshtml | 5 ++++- .../Views/EmailTemplate__EmailQuota.cshtml | 4 ---- .../EmailTemplate__EmailQuotaExhaustedError.cshtml | 6 ++++++ .../Views/EmailTemplate__EmailQuotaWarning.cshtml | 5 ++++- 5 files changed, 23 insertions(+), 8 deletions(-) delete mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml create mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml index 5e2dc03a..4efa6c8f 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml @@ -1,8 +1,15 @@ @if (Model.IsOverQuota) { -

@T["It seems that your site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."]

+

+ @T["It seems that your site sent out more e-mails than the available quota for this month." + + " E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."] +

} else { -

@T["It seems that your site sent out {0}% of e-mails from the available quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.", Model.UsagePercentage]

+

+ @T["It seems that your site sent out {0}% of e-mails from the available quota for this month." + + " E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.", + Model.UsagePercentage] +

} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml index da83fb98..9c09a785 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml @@ -1 +1,4 @@ -

@T["Unless you use your own SMTP server you have limited e-mails to send. You've sent {0} emails from the total of {1}.", Model.CurrentEmailCount, Model.EmailQuota]

+

+ @T["Unless you use your own SMTP server you have limited e-mails to send." + + " You've sent {0} emails from the total of {1}.", Model.CurrentEmailCount, Model.EmailQuota] +

diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml deleted file mode 100644 index 77e87a07..00000000 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuota.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@{ - ViewLayout = "Layout__EmailTemplate"; -} -@T["

Hi,

It seems that your {0} site sent out more e-mails than the available quota for this month. E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank you,
Your Admin Crew

", Model.HostName] diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml new file mode 100644 index 00000000..8e3f38a3 --- /dev/null +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml @@ -0,0 +1,6 @@ +@{ + ViewLayout = "Layout__EmailTemplate"; +} +@T["

Hi,

It seems that your {0} site sent out more e-mails than the available quota for this month." + + " E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank you,
Your Admin Crew

", + Model.HostName] diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml index 06e0179b..1e132c3d 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml @@ -1,4 +1,7 @@ @{ ViewLayout = "Layout__EmailTemplate"; } -@T["

Hi,

It seems that your {0} site sent out {1}% of the available e-mail quota for this month. E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.

Thank you,
Your Admin Crew

", Model.HostName, Model.Percentage] +@T["

Hi,

It seems that your {0} site sent out {1}% of the available e-mail quota for this month." + + " E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota" + + " is exceeded.

Thank you,
Your Admin Crew

", + Model.HostName, Model.Percentage] From a55474093427cf2157dd6d3e8444cc4c62e78ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 13:54:17 +0200 Subject: [PATCH 08/27] Renaming class --- ...s => QuotaManagingSmtpServiceDecorator.cs} | 39 +++++++------------ .../Startup.cs | 2 +- 2 files changed, 14 insertions(+), 27 deletions(-) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/{EmailSenderQuotaService.cs => QuotaManagingSmtpServiceDecorator.cs} (71%) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs similarity index 71% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs index 88403e4a..a31bc0f9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailSenderQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs @@ -10,27 +10,24 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; -public class EmailSenderQuotaService : ISmtpService +public class QuotaManagingSmtpServiceDecorator : ISmtpService { - private readonly IStringLocalizer T; + private readonly IStringLocalizer T; private readonly ISmtpService _smtpService; private readonly IQuotaService _quotaService; - private readonly IEmailQuotaEmailService _emailQuotaEmailService; private readonly ShellSettings _shellSettings; private readonly IEmailTemplateService _emailTemplateService; - public EmailSenderQuotaService( + public QuotaManagingSmtpServiceDecorator( ISmtpService smtpService, - IStringLocalizer stringLocalizer, + IStringLocalizer stringLocalizer, IQuotaService quotaService, - IEmailQuotaEmailService emailQuotaEmailService, ShellSettings shellSettings, IEmailTemplateService emailTemplateService) { _smtpService = smtpService; T = stringLocalizer; _quotaService = quotaService; - _emailQuotaEmailService = emailQuotaEmailService; _shellSettings = shellSettings; _emailTemplateService = emailTemplateService; } @@ -65,45 +62,35 @@ private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) var currentUsagePercentage = _quotaService.CurrentUsagePercentage(emailQuota); if (!_quotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; - var siteOwnerEmails = (await _emailQuotaEmailService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); + var siteOwnerEmails = (await _quotaService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); if (currentUsagePercentage >= 100) { - var emailMessage = new MailMessage - { - Subject = T["[Action Required] Your DotNest site has run over its e-mail quota"], - IsHtmlBody = true, - }; - SendQuotaEmail(siteOwnerEmails, emailMessage, "EmailQuota", currentUsagePercentage); + SendQuotaEmail(siteOwnerEmails, "EmailQuotaExhaustedError", currentUsagePercentage); _quotaService.SaveQuotaReminder(emailQuota); return; } - SendQuotaEmailWithPercentage(siteOwnerEmails, currentUsagePercentage / 10 * 10); + SendQuotaEmail(siteOwnerEmails, $"EmailQuotaWarning", currentUsagePercentage / 10 * 10); _quotaService.SaveQuotaReminder(emailQuota); } - private void SendQuotaEmailWithPercentage( + private void SendQuotaEmail( IEnumerable siteOwnerEmails, + string emailTemplateName, int percentage) { var emailMessage = new MailMessage { - Subject = T["[Warning] Your DotNest site has used {0}% of its e-mail quota", percentage], IsHtmlBody = true, }; - SendQuotaEmail(siteOwnerEmails, emailMessage, $"EmailQuotaWarning", percentage); - } - - private void SendQuotaEmail( - IEnumerable siteOwnerEmails, - MailMessage emailMessage, - string emailTemplateName, - int percentage) - { foreach (var siteOwnerEmail in siteOwnerEmails) { ShellScope.AddDeferredTask(async _ => { + emailMessage.Subject = await _emailTemplateService.RenderEmailTemplateAsync($"{emailTemplateName}_Subject", new + { + Percentage = percentage, + }); emailMessage.To = siteOwnerEmail; emailMessage.Body = await _emailTemplateService.RenderEmailTemplateAsync(emailTemplateName, new { diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs index 9c097bde..03aed370 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs @@ -34,7 +34,7 @@ public override void ConfigureServices(IServiceCollection services) ?? DefaultEmailQuota); services.AddScoped(); - services.Decorate(); + services.Decorate(); services.AddSingleton(); services.Configure(options => From afcdef8846ae26760c699d2bdfa0e424b8315e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 13:54:33 +0200 Subject: [PATCH 09/27] Moving function --- .../Services/EmailQuotaEmailService.cs | 43 ----------------- .../Services/IEmailQuotaEmailService.cs | 17 ------- .../Services/IQuotaService.cs | 3 ++ .../Services/QuotaService.cs | 46 +++++++++++++++---- .../Startup.cs | 2 - 5 files changed, 39 insertions(+), 72 deletions(-) delete mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaEmailService.cs delete mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaEmailService.cs diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaEmailService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaEmailService.cs deleted file mode 100644 index 51b56354..00000000 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaEmailService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using OrchardCore.Security; -using OrchardCore.Security.Services; -using OrchardCore.Users; -using OrchardCore.Users.Models; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using static OrchardCore.Security.Permissions.Permission; -using static OrchardCore.Security.StandardPermissions; - -namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; - -public class EmailQuotaEmailService : IEmailQuotaEmailService -{ - private readonly IRoleService _roleService; - private readonly UserManager _userManager; - - public EmailQuotaEmailService( - IRoleService roleService, - UserManager userManager) - { - _roleService = roleService; - _userManager = userManager; - } - - public async Task> CollectUserEmailsForExceedingQuotaAsync() - { - // Get users with site owner permission. - var roles = await _roleService.GetRolesAsync(); - var siteOwnerRoles = roles.Where(role => - (role as Role)?.RoleClaims.Exists(claim => - claim.ClaimType == ClaimType && claim.ClaimValue == SiteOwner.Name) == true); - - var siteOwners = new List(); - foreach (var role in siteOwnerRoles) - { - siteOwners.AddRange(await _userManager.GetUsersInRoleAsync(role.RoleName)); - } - - return siteOwners.Select(user => (user as User)?.Email); - } -} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaEmailService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaEmailService.cs deleted file mode 100644 index 8b48cd1f..00000000 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaEmailService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using OrchardCore.Email; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; - -/// -/// This service is responsible for creating the email that will be sent to the site owners when the email quota is -/// exceeded. -/// -public interface IEmailQuotaEmailService -{ - /// - /// Creates the that could be sent to the site owners when the email quota is exceeded. - /// - Task> CollectUserEmailsForExceedingQuotaAsync(); -} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs index 4c312786..6d13905b 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs @@ -1,4 +1,5 @@ using Lombiq.Hosting.Tenants.EmailQuotaManagement.Models; +using System.Collections.Generic; using System.Threading.Tasks; namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; @@ -8,6 +9,8 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; /// public interface IQuotaService { + Task> CollectUserEmailsForExceedingQuotaAsync(); + /// /// Checks if the emails should be limited. /// diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs index 930d3f0f..196b5969 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs @@ -1,13 +1,22 @@ using Lombiq.Hosting.Tenants.EmailQuotaManagement.Indexes; using Lombiq.Hosting.Tenants.EmailQuotaManagement.Models; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using OrchardCore.Email; using OrchardCore.Environment.Shell.Configuration; using OrchardCore.Modules; +using OrchardCore.Security; +using OrchardCore.Security.Services; +using OrchardCore.Users; +using OrchardCore.Users.Models; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using YesSql; +using static OrchardCore.Security.Permissions.Permission; +using static OrchardCore.Security.StandardPermissions; namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; @@ -18,19 +27,42 @@ public class QuotaService : IQuotaService private readonly IShellConfiguration _shellConfiguration; private readonly SmtpSettings _smtpOptions; private readonly IClock _clock; + private readonly IRoleService _roleService; + private readonly UserManager _userManager; public QuotaService( ISession session, IOptions emailQuotaOptions, IShellConfiguration shellConfiguration, IOptions smtpOptions, - IClock clock) + IClock clock, + IRoleService roleService, + UserManager userManager) { _session = session; _emailQuotaOptions = emailQuotaOptions.Value; _shellConfiguration = shellConfiguration; _smtpOptions = smtpOptions.Value; _clock = clock; + _roleService = roleService; + _userManager = userManager; + } + + public async Task> CollectUserEmailsForExceedingQuotaAsync() + { + // Get users with site owner permission. + var roles = await _roleService.GetRolesAsync(); + var siteOwnerRoles = roles.Where(role => + (role as Role)?.RoleClaims.Exists(claim => + claim.ClaimType == ClaimType && claim.ClaimValue == SiteOwner.Name) == true); + + var siteOwners = new List(); + foreach (var role in siteOwnerRoles) + { + siteOwners.AddRange(await _userManager.GetUsersInRoleAsync(role.RoleName)); + } + + return siteOwners.Select(user => (user as User)?.Email); } public bool ShouldLimitEmails() @@ -93,15 +125,9 @@ public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentag return true; } - switch (emailQuota.LastReminderPercentage) - { - case >= 80 when currentPercentage < 90: - case >= 90 when currentPercentage < 100: - case >= 100: - return false; - default: - return true; - } + return !((emailQuota.LastReminderPercentage >= 80 && currentPercentage < 90) || + (emailQuota.LastReminderPercentage >= 90 && currentPercentage < 100) || + emailQuota.LastReminderPercentage >= 100); } public void ResetQuota(EmailQuota emailQuota) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs index 03aed370..a9613ced 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs @@ -43,7 +43,5 @@ public override void ConfigureServices(IServiceCollection services) options.Filters.Add(typeof(EmailSettingsQuotaFilter)); } ); - - services.AddScoped(); } } From 42c4343efc8d52d51a9369202c48d48c46218483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 13:54:43 +0200 Subject: [PATCH 10/27] Using generic text --- .../Extensions/TestCaseUITestContextExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index 89855d05..f106ebde 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -13,7 +13,7 @@ public static class TestCaseUITestContextExtensions { private const string SuccessfulSubject = "Successful test message"; private const string UnSuccessfulSubject = "Unsuccessful test message"; - private const string WarningSubject = "[Warning] Your DotNest site has used"; + private const string WarningSubject = "[Warning] Your site has used"; private const string DashboardExceededMessage = "//p[contains(@class,'alert-danger')][contains(.,'It seems that your site sent out more e-mails')]"; @@ -62,7 +62,7 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( await context.GoToSmtpWebUIAsync(); context.CheckExistence(ByHelper.SmtpInboxRow(SuccessfulSubject), exists: true); context.CheckExistence( - ByHelper.SmtpInboxRow("[Action Required] Your DotNest site has run over its e-mail quota"), + ByHelper.SmtpInboxRow("[Action Required] Your site has run over its e-mail quota"), exists: moduleShouldInterfere); var warningMessageExists = context.CheckExistence( ByHelper.SmtpInboxRow(WarningSubject), From 9b67d0a84cd8e3bf28ae52a4e2e63201708faf82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 14:08:35 +0200 Subject: [PATCH 11/27] Renaming files to more descriptive names --- ...ErrorFilter.cs => DashboardQuotaFilter.cs} | 18 +++++++-------- .../Filters/EmailSettingsQuotaFilter.cs | 14 ++++++------ .../Indexes/EmailQuotaIndex.cs | 8 +++---- .../Migrations/EmailQuotaMigrations.cs | 4 ++-- .../Models/EmailQuota.cs | 4 ++-- .../Services/EmailQuotaResetTask.cs | 2 +- .../{QuotaService.cs => EmailQuotaService.cs} | 18 +++++++-------- ...IQuotaService.cs => IEmailQuotaService.cs} | 2 +- .../QuotaManagingSmtpServiceDecorator.cs | 22 +++++++++---------- .../Startup.cs | 4 ++-- ...or.cshtml => DashboardQuotaMessage.cshtml} | 0 ...shtml => EmailSettingsQuotaMessage.cshtml} | 0 12 files changed, 48 insertions(+), 48 deletions(-) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/{EmailQuotaErrorFilter.cs => DashboardQuotaFilter.cs} (76%) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/{QuotaService.cs => EmailQuotaService.cs} (91%) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/{IQuotaService.cs => IEmailQuotaService.cs} (97%) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/{EmailQuotaError.cshtml => DashboardQuotaMessage.cshtml} (100%) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/{EmailSettingsQuota.cshtml => EmailSettingsQuotaMessage.cshtml} (100%) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs similarity index 76% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs index 3122d2c9..a21b7d0a 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailQuotaErrorFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs @@ -9,20 +9,20 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Filters; -public class EmailQuotaErrorFilter : IAsyncResultFilter +public class DashboardQuotaFilter : IAsyncResultFilter { private readonly IShapeFactory _shapeFactory; private readonly ILayoutAccessor _layoutAccessor; - private readonly IQuotaService _quotaService; + private readonly IEmailQuotaService _emailQuotaService; - public EmailQuotaErrorFilter( + public DashboardQuotaFilter( IShapeFactory shapeFactory, ILayoutAccessor layoutAccessor, - IQuotaService quotaService) + IEmailQuotaService emailQuotaService) { _shapeFactory = shapeFactory; _layoutAccessor = layoutAccessor; - _quotaService = quotaService; + _emailQuotaService = emailQuotaService; } public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) @@ -41,18 +41,18 @@ public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultE actionRouteArea == $"{nameof(OrchardCore)}.{nameof(OrchardCore.Admin)}" && actionRouteValue is nameof(AdminController.Index) && context.Result is ViewResult && - _quotaService.ShouldLimitEmails()) + _emailQuotaService.ShouldLimitEmails()) { var layout = await _layoutAccessor.GetLayoutAsync(); var contentZone = layout.Zones["Content"]; - var currentEmailQuota = await _quotaService.IsQuotaOverTheLimitAsync(); + var currentEmailQuota = await _emailQuotaService.IsQuotaOverTheLimitAsync(); - var roundedCurrentPercentage = _quotaService.CurrentUsagePercentage(currentEmailQuota.EmailQuota) / 10 * 10; + var roundedCurrentPercentage = _emailQuotaService.CurrentUsagePercentage(currentEmailQuota.EmailQuota) / 10 * 10; if (roundedCurrentPercentage >= 80) { await contentZone.AddAsync( - await _shapeFactory.CreateAsync("EmailQuotaError", new + await _shapeFactory.CreateAsync("DashboardQuotaMessage", new { currentEmailQuota.IsOverQuota, UsagePercentage = roundedCurrentPercentage, diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs index 7fbca534..28f0421e 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs @@ -15,18 +15,18 @@ public class EmailSettingsQuotaFilter : IAsyncResultFilter { private readonly IShapeFactory _shapeFactory; private readonly ILayoutAccessor _layoutAccessor; - private readonly IQuotaService _quotaService; + private readonly IEmailQuotaService _emailQuotaService; private readonly EmailQuotaOptions _emailQuotaOptions; public EmailSettingsQuotaFilter( IShapeFactory shapeFactory, ILayoutAccessor layoutAccessor, - IQuotaService quotaService, + IEmailQuotaService emailQuotaService, IOptions emailQuotaOptions) { _shapeFactory = shapeFactory; _layoutAccessor = layoutAccessor; - _quotaService = quotaService; + _emailQuotaService = emailQuotaService; _emailQuotaOptions = emailQuotaOptions.Value; } @@ -48,16 +48,16 @@ actionRouteValue is nameof(AdminController.Index) && context.Result is ViewResult && context.RouteData.Values.TryGetValue("GroupId", out var groupId) && (string)groupId == "email" && - _quotaService.ShouldLimitEmails()) + _emailQuotaService.ShouldLimitEmails()) { var layout = await _layoutAccessor.GetLayoutAsync(); var contentZone = layout.Zones["Content"]; - var quota = await _quotaService.GetCurrentQuotaAsync(); + var quota = await _emailQuotaService.GetCurrentQuotaAsync(); await contentZone.AddAsync( - await _shapeFactory.CreateAsync("EmailSettingsQuota", new + await _shapeFactory.CreateAsync("EmailSettingsQuotaMessage", new { - CurrentEmailCount = quota.CurrentEmailQuotaCount, + CurrentEmailCount = quota.CurrentEmailUsageCount, EmailQuota = _emailQuotaOptions.EmailQuotaPerMonth, }), "0"); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs index 48ac00e0..7bac0f86 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Indexes/EmailQuotaIndex.cs @@ -6,8 +6,8 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Indexes; public class EmailQuotaIndex : MapIndex { - public int CurrentEmailQuotaCount { get; set; } - public DateTime LastReminder { get; set; } + public int CurrentEmailUsageCount { get; set; } + public DateTime LastReminderUtc { get; set; } public int LastReminderPercentage { get; set; } } @@ -17,8 +17,8 @@ public override void Describe(DescribeContext context) => context.For() .Map(emailQuota => new EmailQuotaIndex { - CurrentEmailQuotaCount = emailQuota.CurrentEmailQuotaCount, - LastReminder = emailQuota.LastReminder, + CurrentEmailUsageCount = emailQuota.CurrentEmailUsageCount, + LastReminderUtc = emailQuota.LastReminderUtc, LastReminderPercentage = emailQuota.LastReminderPercentage, }); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs index 6460449a..77426ccf 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Migrations/EmailQuotaMigrations.cs @@ -10,8 +10,8 @@ public class EmailQuotaMigrations : DataMigration public int Create() { SchemaBuilder.CreateMapIndexTable( - table => table.Column(nameof(EmailQuotaIndex.CurrentEmailQuotaCount)) - .Column(nameof(EmailQuotaIndex.LastReminder)) + table => table.Column(nameof(EmailQuotaIndex.CurrentEmailUsageCount)) + .Column(nameof(EmailQuotaIndex.LastReminderUtc)) .Column(nameof(EmailQuotaIndex.LastReminderPercentage))); return 2; diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs index 6efd6c9c..ed54e384 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs @@ -4,7 +4,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Models; public class EmailQuota { - public int CurrentEmailQuotaCount { get; set; } - public DateTime LastReminder { get; set; } + public int CurrentEmailUsageCount { get; set; } + public DateTime LastReminderUtc { get; set; } public int LastReminderPercentage { get; set; } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs index 3ca811cc..c16c470c 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs @@ -13,7 +13,7 @@ public class EmailQuotaResetBackgroundTask : IBackgroundTask { public async Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) { - var quotaService = serviceProvider.GetRequiredService(); + var quotaService = serviceProvider.GetRequiredService(); var currentQuota = await quotaService.GetCurrentQuotaAsync(); quotaService.ResetQuota(currentQuota); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs similarity index 91% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs index 196b5969..9576da18 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs @@ -20,7 +20,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; -public class QuotaService : IQuotaService +public class EmailQuotaService : IEmailQuotaService { private readonly ISession _session; private readonly EmailQuotaOptions _emailQuotaOptions; @@ -30,7 +30,7 @@ public class QuotaService : IQuotaService private readonly IRoleService _roleService; private readonly UserManager _userManager; - public QuotaService( + public EmailQuotaService( ISession session, IOptions emailQuotaOptions, IShellConfiguration shellConfiguration, @@ -76,7 +76,7 @@ public async Task IsQuotaOverTheLimitAsync() var currentQuota = await GetCurrentQuotaAsync(); return new QuotaResult { - IsOverQuota = _emailQuotaOptions.EmailQuotaPerMonth <= currentQuota.CurrentEmailQuotaCount, + IsOverQuota = _emailQuotaOptions.EmailQuotaPerMonth <= currentQuota.CurrentEmailUsageCount, EmailQuota = currentQuota, }; } @@ -90,7 +90,7 @@ public async Task GetCurrentQuotaAsync() currentQuota = new EmailQuota { // Need to set default value otherwise the database might complain about being 01/01/0001 out of range. - LastReminder = _clock.UtcNow.AddMonths(-1), + LastReminderUtc = _clock.UtcNow.AddMonths(-1), }; _session.Save(currentQuota); @@ -99,13 +99,13 @@ public async Task GetCurrentQuotaAsync() public void IncreaseQuota(EmailQuota emailQuota) { - emailQuota.CurrentEmailQuotaCount++; + emailQuota.CurrentEmailUsageCount++; _session.Save(emailQuota); } public void SaveQuotaReminder(EmailQuota emailQuota) { - emailQuota.LastReminder = _clock.UtcNow; + emailQuota.LastReminderUtc = _clock.UtcNow; emailQuota.LastReminderPercentage = CurrentUsagePercentage(emailQuota); _session.Save(emailQuota); } @@ -118,7 +118,7 @@ public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentag return false; } - var isSameMonth = IsSameMonth(_clock.UtcNow, emailQuota.LastReminder); + var isSameMonth = IsSameMonth(_clock.UtcNow, emailQuota.LastReminderUtc); if (!isSameMonth) { @@ -132,12 +132,12 @@ public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentag public void ResetQuota(EmailQuota emailQuota) { - emailQuota.CurrentEmailQuotaCount = 0; + emailQuota.CurrentEmailUsageCount = 0; _session.Save(emailQuota); } public int CurrentUsagePercentage(EmailQuota emailQuota) => - Convert.ToInt32(Math.Round((double)emailQuota.CurrentEmailQuotaCount / _emailQuotaOptions.EmailQuotaPerMonth * 100, 0)); + Convert.ToInt32(Math.Round((double)emailQuota.CurrentEmailUsageCount / _emailQuotaOptions.EmailQuotaPerMonth * 100, 0)); private static bool IsSameMonth(DateTime date1, DateTime date2) => date1.Month == date2.Month && date1.Year == date2.Year; diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs similarity index 97% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index 6d13905b..39166aaf 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -7,7 +7,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; /// /// A service that is responsible for managing the quota of sent emails. /// -public interface IQuotaService +public interface IEmailQuotaService { Task> CollectUserEmailsForExceedingQuotaAsync(); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs index a31bc0f9..1c8195c0 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs @@ -14,32 +14,32 @@ public class QuotaManagingSmtpServiceDecorator : ISmtpService { private readonly IStringLocalizer T; private readonly ISmtpService _smtpService; - private readonly IQuotaService _quotaService; + private readonly IEmailQuotaService _emailQuotaService; private readonly ShellSettings _shellSettings; private readonly IEmailTemplateService _emailTemplateService; public QuotaManagingSmtpServiceDecorator( ISmtpService smtpService, IStringLocalizer stringLocalizer, - IQuotaService quotaService, + IEmailQuotaService emailQuotaService, ShellSettings shellSettings, IEmailTemplateService emailTemplateService) { _smtpService = smtpService; T = stringLocalizer; - _quotaService = quotaService; + _emailQuotaService = emailQuotaService; _shellSettings = shellSettings; _emailTemplateService = emailTemplateService; } public async Task SendAsync(MailMessage message) { - if (!_quotaService.ShouldLimitEmails()) + if (!_emailQuotaService.ShouldLimitEmails()) { return await _smtpService.SendAsync(message); } - var isQuotaOverResult = await _quotaService.IsQuotaOverTheLimitAsync(); + var isQuotaOverResult = await _emailQuotaService.IsQuotaOverTheLimitAsync(); await SendAlertEmailIfNecessaryAsync(isQuotaOverResult.EmailQuota); // Should send the email if the quota is not over the limit. @@ -51,7 +51,7 @@ public async Task SendAsync(MailMessage message) var emailResult = await _smtpService.SendAsync(message); if (emailResult == SmtpResult.Success) { - _quotaService.IncreaseQuota(isQuotaOverResult.EmailQuota); + _emailQuotaService.IncreaseQuota(isQuotaOverResult.EmailQuota); } return emailResult; @@ -59,19 +59,19 @@ public async Task SendAsync(MailMessage message) private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) { - var currentUsagePercentage = _quotaService.CurrentUsagePercentage(emailQuota); - if (!_quotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; + var currentUsagePercentage = _emailQuotaService.CurrentUsagePercentage(emailQuota); + if (!_emailQuotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; - var siteOwnerEmails = (await _quotaService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); + var siteOwnerEmails = (await _emailQuotaService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); if (currentUsagePercentage >= 100) { SendQuotaEmail(siteOwnerEmails, "EmailQuotaExhaustedError", currentUsagePercentage); - _quotaService.SaveQuotaReminder(emailQuota); + _emailQuotaService.SaveQuotaReminder(emailQuota); return; } SendQuotaEmail(siteOwnerEmails, $"EmailQuotaWarning", currentUsagePercentage / 10 * 10); - _quotaService.SaveQuotaReminder(emailQuota); + _emailQuotaService.SaveQuotaReminder(emailQuota); } private void SendQuotaEmail( diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs index a9613ced..2b61367b 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs @@ -33,13 +33,13 @@ public override void ConfigureServices(IServiceCollection services) options.EmailQuotaPerMonth = _shellConfiguration.GetValue("Lombiq_Hosting_Tenants_EmailQuotaManagement:EmailQuotaPerMonth") ?? DefaultEmailQuota); - services.AddScoped(); + services.AddScoped(); services.Decorate(); services.AddSingleton(); services.Configure(options => { - options.Filters.Add(typeof(EmailQuotaErrorFilter)); + options.Filters.Add(typeof(DashboardQuotaFilter)); options.Filters.Add(typeof(EmailSettingsQuotaFilter)); } ); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml similarity index 100% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailQuotaError.cshtml rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml similarity index 100% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuota.cshtml rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml From 6a67c4c68886a127bd964cfadaa1fec8d7a75e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 14:36:29 +0200 Subject: [PATCH 12/27] Adding email quota subject service --- .../Services/EmailQuotaSubjectService.cs | 17 +++++++++++++++++ .../Services/IEmailQuotaSubjectService.cs | 9 +++++++++ .../Startup.cs | 1 + 3 files changed, 27 insertions(+) create mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaSubjectService.cs create mode 100644 Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaSubjectService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaSubjectService.cs new file mode 100644 index 00000000..433c8ab7 --- /dev/null +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaSubjectService.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.Localization; + +namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; + +public class EmailQuotaSubjectService : IEmailQuotaSubjectService +{ + private readonly IStringLocalizer T; + + public EmailQuotaSubjectService(IStringLocalizer stringLocalizer) => + T = stringLocalizer; + + public LocalizedString GetWarningEmailSubject(int percentage) => + T["[Warning] Your site has used {0}% of its e-mail quota", percentage]; + + public LocalizedString GetExceededEmailSubject() => + T["[Action Required] Your site has run over its e-mail quota"]; +} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs new file mode 100644 index 00000000..3e36189f --- /dev/null +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.Localization; + +namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; + +public interface IEmailQuotaSubjectService +{ + public LocalizedString GetWarningEmailSubject(int percentage); + public LocalizedString GetExceededEmailSubject(); +} diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs index 2b61367b..91a9cecc 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs @@ -43,5 +43,6 @@ public override void ConfigureServices(IServiceCollection services) options.Filters.Add(typeof(EmailSettingsQuotaFilter)); } ); + services.AddScoped(); } } From 81e79980e0b37fb79a82465eb9821e1e53f5c8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 14:36:42 +0200 Subject: [PATCH 13/27] Renaming and code cleanups --- .../Filters/DashboardQuotaFilter.cs | 7 +++-- .../Filters/EmailSettingsQuotaFilter.cs | 2 +- .../Models/EmailQuota.cs | 3 ++ .../Services/EmailQuotaResetTask.cs | 6 ++-- .../Services/EmailQuotaService.cs | 21 +++++++------- .../Services/IEmailQuotaService.cs | 12 ++++---- .../QuotaManagingSmtpServiceDecorator.cs | 28 +++++++++++++------ .../Startup.cs | 10 ++++--- ...lTemplate__EmailQuotaExceededError.cshtml} | 0 9 files changed, 51 insertions(+), 38 deletions(-) rename Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/{EmailTemplate__EmailQuotaExhaustedError.cshtml => EmailTemplate__EmailQuotaExceededError.cshtml} (100%) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs index a21b7d0a..39649395 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/DashboardQuotaFilter.cs @@ -47,15 +47,16 @@ context.Result is ViewResult && var contentZone = layout.Zones["Content"]; var currentEmailQuota = await _emailQuotaService.IsQuotaOverTheLimitAsync(); - var roundedCurrentPercentage = _emailQuotaService.CurrentUsagePercentage(currentEmailQuota.EmailQuota) / 10 * 10; + var currentUsagePercentage = currentEmailQuota.EmailQuota + .CurrentUsagePercentage(_emailQuotaService.GetEmailQuotaPerMonth()); - if (roundedCurrentPercentage >= 80) + if (currentUsagePercentage >= 80) { await contentZone.AddAsync( await _shapeFactory.CreateAsync("DashboardQuotaMessage", new { currentEmailQuota.IsOverQuota, - UsagePercentage = roundedCurrentPercentage, + UsagePercentage = currentUsagePercentage, }), "0"); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs index 28f0421e..f253d4bd 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs @@ -53,7 +53,7 @@ context.Result is ViewResult && var layout = await _layoutAccessor.GetLayoutAsync(); var contentZone = layout.Zones["Content"]; - var quota = await _emailQuotaService.GetCurrentQuotaAsync(); + var quota = await _emailQuotaService.GetOrCreateCurrentQuotaAsync(); await contentZone.AddAsync( await _shapeFactory.CreateAsync("EmailSettingsQuotaMessage", new { diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs index ed54e384..905ef04d 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Models/EmailQuota.cs @@ -7,4 +7,7 @@ public class EmailQuota public int CurrentEmailUsageCount { get; set; } public DateTime LastReminderUtc { get; set; } public int LastReminderPercentage { get; set; } + + public int CurrentUsagePercentage(int emailQuotaPerMonth) => + Convert.ToInt32(Math.Round((double)CurrentEmailUsageCount / emailQuotaPerMonth * 100, 0)); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs index c16c470c..2a8c7d93 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaResetTask.cs @@ -13,8 +13,8 @@ public class EmailQuotaResetBackgroundTask : IBackgroundTask { public async Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) { - var quotaService = serviceProvider.GetRequiredService(); - var currentQuota = await quotaService.GetCurrentQuotaAsync(); - quotaService.ResetQuota(currentQuota); + var emailQuotaService = serviceProvider.GetRequiredService(); + var currentQuota = await emailQuotaService.GetOrCreateCurrentQuotaAsync(); + emailQuotaService.ResetQuota(currentQuota); } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs index 9576da18..6c6a9bb9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs @@ -48,7 +48,7 @@ public EmailQuotaService( _userManager = userManager; } - public async Task> CollectUserEmailsForExceedingQuotaAsync() + public async Task> CollectUserEmailsForEmailReminderAsync() { // Get users with site owner permission. var roles = await _roleService.GetRolesAsync(); @@ -73,7 +73,7 @@ public bool ShouldLimitEmails() public async Task IsQuotaOverTheLimitAsync() { - var currentQuota = await GetCurrentQuotaAsync(); + var currentQuota = await GetOrCreateCurrentQuotaAsync(); return new QuotaResult { IsOverQuota = _emailQuotaOptions.EmailQuotaPerMonth <= currentQuota.CurrentEmailUsageCount, @@ -81,7 +81,7 @@ public async Task IsQuotaOverTheLimitAsync() }; } - public async Task GetCurrentQuotaAsync() + public async Task GetOrCreateCurrentQuotaAsync() { var currentQuota = await _session.Query().FirstOrDefaultAsync(); @@ -106,14 +106,13 @@ public void IncreaseQuota(EmailQuota emailQuota) public void SaveQuotaReminder(EmailQuota emailQuota) { emailQuota.LastReminderUtc = _clock.UtcNow; - emailQuota.LastReminderPercentage = CurrentUsagePercentage(emailQuota); + emailQuota.LastReminderPercentage = emailQuota.CurrentUsagePercentage(GetEmailQuotaPerMonth()); _session.Save(emailQuota); } - public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentage = null) + public bool ShouldSendReminderEmail(EmailQuota emailQuota, int currentUsagePercentage) { - currentPercentage ??= CurrentUsagePercentage(emailQuota); - if (currentPercentage < 80) + if (currentUsagePercentage < 80) { return false; } @@ -125,8 +124,8 @@ public bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentag return true; } - return !((emailQuota.LastReminderPercentage >= 80 && currentPercentage < 90) || - (emailQuota.LastReminderPercentage >= 90 && currentPercentage < 100) || + return !((emailQuota.LastReminderPercentage >= 80 && currentUsagePercentage < 90) || + (emailQuota.LastReminderPercentage >= 90 && currentUsagePercentage < 100) || emailQuota.LastReminderPercentage >= 100); } @@ -136,8 +135,8 @@ public void ResetQuota(EmailQuota emailQuota) _session.Save(emailQuota); } - public int CurrentUsagePercentage(EmailQuota emailQuota) => - Convert.ToInt32(Math.Round((double)emailQuota.CurrentEmailUsageCount / _emailQuotaOptions.EmailQuotaPerMonth * 100, 0)); + public int GetEmailQuotaPerMonth() => + _emailQuotaOptions.EmailQuotaPerMonth; private static bool IsSameMonth(DateTime date1, DateTime date2) => date1.Month == date2.Month && date1.Year == date2.Year; diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index 39166aaf..a3b7fcd1 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -9,7 +9,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; /// public interface IEmailQuotaService { - Task> CollectUserEmailsForExceedingQuotaAsync(); + Task> CollectUserEmailsForEmailReminderAsync(); /// /// Checks if the emails should be limited. @@ -24,7 +24,7 @@ public interface IEmailQuotaService /// /// Gets the current quota. /// - Task GetCurrentQuotaAsync(); + Task GetOrCreateCurrentQuotaAsync(); /// /// Increases the given quota value. @@ -44,10 +44,8 @@ public interface IEmailQuotaService /// /// Returns if the reminder email should be sent. /// - bool ShouldSendReminderEmail(EmailQuota emailQuota, int? currentPercentage = null); + bool ShouldSendReminderEmail(EmailQuota emailQuota, int currentUsagePercentage); - /// - /// Returns the current quota usage percentage. - /// - int CurrentUsagePercentage(EmailQuota emailQuota); + + int GetEmailQuotaPerMonth(); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs index 1c8195c0..974d3fa9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs @@ -17,19 +17,22 @@ public class QuotaManagingSmtpServiceDecorator : ISmtpService private readonly IEmailQuotaService _emailQuotaService; private readonly ShellSettings _shellSettings; private readonly IEmailTemplateService _emailTemplateService; + private readonly IEmailQuotaSubjectService _emailQuotaSubjectService; public QuotaManagingSmtpServiceDecorator( ISmtpService smtpService, IStringLocalizer stringLocalizer, IEmailQuotaService emailQuotaService, ShellSettings shellSettings, - IEmailTemplateService emailTemplateService) + IEmailTemplateService emailTemplateService, + IEmailQuotaSubjectService emailQuotaSubjectService) { _smtpService = smtpService; T = stringLocalizer; _emailQuotaService = emailQuotaService; _shellSettings = shellSettings; _emailTemplateService = emailTemplateService; + _emailQuotaSubjectService = emailQuotaSubjectService; } public async Task SendAsync(MailMessage message) @@ -59,38 +62,45 @@ public async Task SendAsync(MailMessage message) private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) { - var currentUsagePercentage = _emailQuotaService.CurrentUsagePercentage(emailQuota); + var currentUsagePercentage = emailQuota.CurrentUsagePercentage(_emailQuotaService.GetEmailQuotaPerMonth()); if (!_emailQuotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; - var siteOwnerEmails = (await _emailQuotaService.CollectUserEmailsForExceedingQuotaAsync()).ToList(); + var siteOwnerEmails = (await _emailQuotaService.CollectUserEmailsForEmailReminderAsync()).ToList(); if (currentUsagePercentage >= 100) { - SendQuotaEmail(siteOwnerEmails, "EmailQuotaExhaustedError", currentUsagePercentage); + SendQuotaEmail( + siteOwnerEmails, + "EmailQuotaExceededError", + _emailQuotaSubjectService.GetExceededEmailSubject(), + currentUsagePercentage); _emailQuotaService.SaveQuotaReminder(emailQuota); return; } - SendQuotaEmail(siteOwnerEmails, $"EmailQuotaWarning", currentUsagePercentage / 10 * 10); + SendQuotaEmail( + siteOwnerEmails, + $"EmailQuotaWarning", + _emailQuotaSubjectService.GetWarningEmailSubject(currentUsagePercentage), + currentUsagePercentage + ); _emailQuotaService.SaveQuotaReminder(emailQuota); } private void SendQuotaEmail( IEnumerable siteOwnerEmails, string emailTemplateName, + string subject, int percentage) { var emailMessage = new MailMessage { IsHtmlBody = true, + Subject = subject, }; foreach (var siteOwnerEmail in siteOwnerEmails) { ShellScope.AddDeferredTask(async _ => { - emailMessage.Subject = await _emailTemplateService.RenderEmailTemplateAsync($"{emailTemplateName}_Subject", new - { - Percentage = percentage, - }); emailMessage.To = siteOwnerEmail; emailMessage.Body = await _emailTemplateService.RenderEmailTemplateAsync(emailTemplateName, new { diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs index 91a9cecc..d1baa20c 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Startup.cs @@ -29,20 +29,22 @@ public override void ConfigureServices(IServiceCollection services) { services.AddDataMigration(); services.AddSingleton(); + services.AddSingleton(); + services.Configure(options => options.EmailQuotaPerMonth = _shellConfiguration.GetValue("Lombiq_Hosting_Tenants_EmailQuotaManagement:EmailQuotaPerMonth") ?? DefaultEmailQuota); - services.AddScoped(); - services.Decorate(); - services.AddSingleton(); - services.Configure(options => { options.Filters.Add(typeof(DashboardQuotaFilter)); options.Filters.Add(typeof(EmailSettingsQuotaFilter)); } ); + + services.AddScoped(); services.AddScoped(); + + services.Decorate(); } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml similarity index 100% rename from Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExhaustedError.cshtml rename to Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml From e2c195e6c0697367c54a164097e54d5e2d86e413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 15:12:08 +0200 Subject: [PATCH 14/27] Cleanup and additional docs --- .../Filters/EmailSettingsQuotaFilter.cs | 11 ++----- .../Services/EmailQuotaService.cs | 4 +-- .../Services/IEmailQuotaService.cs | 30 ++++++++++++------- .../Services/IEmailQuotaSubjectService.cs | 11 +++++++ .../QuotaManagingSmtpServiceDecorator.cs | 12 ++++---- .../Views/EmailSettingsQuotaMessage.cshtml | 2 +- 6 files changed, 44 insertions(+), 26 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs index f253d4bd..b4543ede 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Filters/EmailSettingsQuotaFilter.cs @@ -1,8 +1,6 @@ -using Lombiq.Hosting.Tenants.EmailQuotaManagement.Models; using Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.Options; using OrchardCore.DisplayManagement; using OrchardCore.DisplayManagement.Layout; using OrchardCore.Mvc.Core.Utilities; @@ -16,18 +14,15 @@ public class EmailSettingsQuotaFilter : IAsyncResultFilter private readonly IShapeFactory _shapeFactory; private readonly ILayoutAccessor _layoutAccessor; private readonly IEmailQuotaService _emailQuotaService; - private readonly EmailQuotaOptions _emailQuotaOptions; public EmailSettingsQuotaFilter( IShapeFactory shapeFactory, ILayoutAccessor layoutAccessor, - IEmailQuotaService emailQuotaService, - IOptions emailQuotaOptions) + IEmailQuotaService emailQuotaService) { _shapeFactory = shapeFactory; _layoutAccessor = layoutAccessor; _emailQuotaService = emailQuotaService; - _emailQuotaOptions = emailQuotaOptions.Value; } public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) @@ -57,8 +52,8 @@ context.Result is ViewResult && await contentZone.AddAsync( await _shapeFactory.CreateAsync("EmailSettingsQuotaMessage", new { - CurrentEmailCount = quota.CurrentEmailUsageCount, - EmailQuota = _emailQuotaOptions.EmailQuotaPerMonth, + quota.CurrentEmailUsageCount, + EmailQuotaPerMonth = _emailQuotaService.GetEmailQuotaPerMonth(), }), "0"); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs index 6c6a9bb9..fac73549 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs @@ -97,13 +97,13 @@ public async Task GetOrCreateCurrentQuotaAsync() return currentQuota; } - public void IncreaseQuota(EmailQuota emailQuota) + public void IncreaseEmailUsage(EmailQuota emailQuota) { emailQuota.CurrentEmailUsageCount++; _session.Save(emailQuota); } - public void SaveQuotaReminder(EmailQuota emailQuota) + public void SetQuotaOnEmailReminder(EmailQuota emailQuota) { emailQuota.LastReminderUtc = _clock.UtcNow; emailQuota.LastReminderPercentage = emailQuota.CurrentUsagePercentage(GetEmailQuotaPerMonth()); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index a3b7fcd1..8452b693 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -9,43 +9,53 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; /// public interface IEmailQuotaService { + /// + /// Collects the emails of the users who should receive the email reminder, based on the site owner permission. + /// Task> CollectUserEmailsForEmailReminderAsync(); /// - /// Checks if the emails should be limited. + /// Checks if the emails should be limited, depending on the default SMTP settings. /// bool ShouldLimitEmails(); /// - /// Checks if the quota is over the limit. + /// Checks if the current email usage is over monthly limit, returns a object that + /// contains the and in the if + /// it is over the limit. /// Task IsQuotaOverTheLimitAsync(); /// - /// Gets the current quota. + /// Gets or creates the in the database. /// Task GetOrCreateCurrentQuotaAsync(); /// - /// Increases the given quota value. + /// Increases the usage count of the given and saves to the database. /// - void IncreaseQuota(EmailQuota emailQuota); + void IncreaseEmailUsage(EmailQuota emailQuota); /// - /// Resets the given quota to 0. + /// Resets the given to 0 and saves to + /// the database. /// void ResetQuota(EmailQuota emailQuota); /// - /// Saves the given quota on reminder sent. + /// Sets the to the current date and + /// to the current email quota usage percentage then saves to the + /// database. /// - void SaveQuotaReminder(EmailQuota emailQuota); + void SetQuotaOnEmailReminder(EmailQuota emailQuota); /// - /// Returns if the reminder email should be sent. + /// Returns , if the reminder email should be sent. /// bool ShouldSendReminderEmail(EmailQuota emailQuota, int currentUsagePercentage); - + /// + /// Return the email quota per month value from the configuration. + /// int GetEmailQuotaPerMonth(); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs index 3e36189f..04f429c9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs @@ -2,8 +2,19 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; +/// +/// Service for getting the subject of the email sent when the email quota is exceeded or when it's close to being exceeded. +/// public interface IEmailQuotaSubjectService { + /// + /// Gets the subject of the email sent for the email when the email usage is above 80%. + /// + /// The current usage percentage. public LocalizedString GetWarningEmailSubject(int percentage); + + /// + /// Gets the subject of the email sent for the email quota exceeded email. + /// public LocalizedString GetExceededEmailSubject(); } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs index 974d3fa9..bad5213c 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs @@ -54,7 +54,7 @@ public async Task SendAsync(MailMessage message) var emailResult = await _smtpService.SendAsync(message); if (emailResult == SmtpResult.Success) { - _emailQuotaService.IncreaseQuota(isQuotaOverResult.EmailQuota); + _emailQuotaService.IncreaseEmailUsage(isQuotaOverResult.EmailQuota); } return emailResult; @@ -69,24 +69,24 @@ private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) if (currentUsagePercentage >= 100) { SendQuotaEmail( + emailQuota, siteOwnerEmails, "EmailQuotaExceededError", _emailQuotaSubjectService.GetExceededEmailSubject(), currentUsagePercentage); - _emailQuotaService.SaveQuotaReminder(emailQuota); return; } SendQuotaEmail( + emailQuota, siteOwnerEmails, $"EmailQuotaWarning", _emailQuotaSubjectService.GetWarningEmailSubject(currentUsagePercentage), - currentUsagePercentage - ); - _emailQuotaService.SaveQuotaReminder(emailQuota); + currentUsagePercentage); } private void SendQuotaEmail( + EmailQuota emailQuota, IEnumerable siteOwnerEmails, string emailTemplateName, string subject, @@ -112,5 +112,7 @@ private void SendQuotaEmail( await _smtpService.SendAsync(emailMessage); }); } + + _emailQuotaService.SetQuotaOnEmailReminder(emailQuota); } } diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml index 9c09a785..3d5ff8a8 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml @@ -1,4 +1,4 @@

@T["Unless you use your own SMTP server you have limited e-mails to send." + - " You've sent {0} emails from the total of {1}.", Model.CurrentEmailCount, Model.EmailQuota] + " You've sent {0} emails from the total of {1}.", Model.CurrentEmailUsageCount, Model.EmailQuotaPerMonth]

From dd1653880f3b278f9062c3f9d9250e43c7bcc86c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 15:31:31 +0200 Subject: [PATCH 15/27] Should only check if necessary --- .../Extensions/TestCaseUITestContextExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index f106ebde..b33e96ed 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -67,7 +67,7 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( var warningMessageExists = context.CheckExistence( ByHelper.SmtpInboxRow(WarningSubject), exists: moduleShouldInterfere); - if (warningMessageExists) + if (moduleShouldInterfere && warningMessageExists) { (context.GetAll( ByHelper.SmtpInboxRow(WarningSubject)).Count == warningEmails.Count) From 3e0b148c800272973896e8e3f3f22bb3ec55c020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 15:31:42 +0200 Subject: [PATCH 16/27] Code cleanup --- .../Extensions/TestCaseUITestContextExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index b33e96ed..7434f43f 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -42,7 +42,7 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( if (warningLevel >= 100) { await context.GoToDashboardAsync(); - context.CheckExistence(By.XPath(DashboardExceededMessage), exists: moduleShouldInterfere); + context.CheckExistence(By.XPath(DashboardExceededMessage), exists: true); } else if (warningLevel >= 80) { @@ -50,7 +50,7 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( context.CheckExistence( By.XPath($"//p[contains(@class,'alert-warning')]" + $"[contains(.,'It seems that your site sent out {warningLevel.ToTechnicalString()}% of e-mail')]"), - exists: moduleShouldInterfere); + exists: true); if (!warningEmails.Contains(warningLevel)) { warningEmails.Add(warningLevel); From 8d7c65d57559793986391d50465b8b8934ad435f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Fri, 29 Sep 2023 15:31:57 +0200 Subject: [PATCH 17/27] Using same rounding as module --- .../Extensions/TestCaseUITestContextExtensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs index 7434f43f..e635c1b1 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement.Tests.UI/Extensions/TestCaseUITestContextExtensions.cs @@ -36,7 +36,8 @@ public static async Task TestEmailQuotaManagementBehaviorAsync( await SendTestEmailAsync(context, SuccessfulSubject); context.SuccessMessageExists(); CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, i + 1); - var warningLevel = Convert.ToInt32((double)(i + 1) / maximumEmailQuota * 100) / 10 * 10; + var warningLevel = Convert.ToInt32(Math.Round((double)(i + 1) / maximumEmailQuota * 100, 0)); + if (!moduleShouldInterfere) continue; if (warningLevel >= 100) From e08b7218f7c61b0e6ad4183ccaf1bbced9cc128e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:10 +0200 Subject: [PATCH 18/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Views/DashboardQuotaMessage.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml index 4efa6c8f..b90269a9 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml @@ -1,8 +1,8 @@ @if (Model.IsOverQuota) {

- @T["It seems that your site sent out more e-mails than the available quota for this month." + - " E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."] + @T["It seems that your site sent out more e-mails than the available quota for this month. " + + "E-mail sending has been stopped until next month (any feature sending out e-mails will fail)."]

} else From 930ea8089bebfc70f759e1297acc58a7cceda063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:18 +0200 Subject: [PATCH 19/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Views/DashboardQuotaMessage.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml index b90269a9..358de90a 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuotaMessage.cshtml @@ -8,8 +8,8 @@ else {

- @T["It seems that your site sent out {0}% of e-mails from the available quota for this month." + - " E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.", + @T["It seems that your site sent out {0}% of e-mails from the available quota for this month. " + + "E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota is exceeded.", Model.UsagePercentage]

} From 4f55268b8c4821d9d3004cca68a12169d781d3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:28 +0200 Subject: [PATCH 20/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Views/EmailSettingsQuotaMessage.cshtml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml index 3d5ff8a8..5e7d8cae 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSettingsQuotaMessage.cshtml @@ -1,4 +1,6 @@

- @T["Unless you use your own SMTP server you have limited e-mails to send." + - " You've sent {0} emails from the total of {1}.", Model.CurrentEmailUsageCount, Model.EmailQuotaPerMonth] + @T["Unless you use your own SMTP server you have limited e-mails to send. " + + "You've sent {0} emails from the total of {1}.", + Model.CurrentEmailUsageCount, + Model.EmailQuotaPerMonth]

From 1b0e8dab5e7ca551815db73f5d25280db2b0cded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:34 +0200 Subject: [PATCH 21/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Views/EmailTemplate__EmailQuotaExceededError.cshtml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml index 8e3f38a3..e4001487 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaExceededError.cshtml @@ -1,6 +1,7 @@ @{ ViewLayout = "Layout__EmailTemplate"; } -@T["

Hi,

It seems that your {0} site sent out more e-mails than the available quota for this month." + - " E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank you,
Your Admin Crew

", +@T["

Hi,

It seems that your {0} site sent out more e-mails than the available quota for this month. " + + "E-mail sending has been stopped until next month (any feature sending out e-mails will fail).

Thank " + + "you,
Your Admin Crew

", Model.HostName] From 65b7a37a80842733d221856a8a5cabf7c1fe7cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:43 +0200 Subject: [PATCH 22/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Views/EmailTemplate__EmailQuotaWarning.cshtml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml index 1e132c3d..817b2a5e 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplate__EmailQuotaWarning.cshtml @@ -1,7 +1,8 @@ @{ ViewLayout = "Layout__EmailTemplate"; } -@T["

Hi,

It seems that your {0} site sent out {1}% of the available e-mail quota for this month." + - " E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota" + - " is exceeded.

Thank you,
Your Admin Crew

", - Model.HostName, Model.Percentage] +@T["

Hi,

It seems that your {0} site sent out {1}% of the available e-mail quota for this month. " + + "E-mail sending will be stopped until next month (any feature sending out e-mails will fail), when the quota " + + "is exceeded.

Thank you,
Your Admin Crew

", + Model.HostName, + Model.Percentage] From 301666cdfa5532bc69b6c6bc52f74d9b024133e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:35:56 +0200 Subject: [PATCH 23/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/IEmailQuotaService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index 8452b693..0456f71b 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -32,7 +32,7 @@ public interface IEmailQuotaService Task GetOrCreateCurrentQuotaAsync(); /// - /// Increases the usage count of the given and saves to the database. + /// Increases the usage count of the given and saves it to the database. /// void IncreaseEmailUsage(EmailQuota emailQuota); From 602d93bfa691c6f5bd7ee27d84188718b7e3e01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:36:04 +0200 Subject: [PATCH 24/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/IEmailQuotaService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index 0456f71b..99c25221 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -37,8 +37,8 @@ public interface IEmailQuotaService void IncreaseEmailUsage(EmailQuota emailQuota); /// - /// Resets the given to 0 and saves to - /// the database. + /// Resets the given to 0 and saves it + /// to the database. /// void ResetQuota(EmailQuota emailQuota); From 00046f559c66b765287a07ae0c1dc50d715181b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:36:09 +0200 Subject: [PATCH 25/27] Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Lehóczky --- .../Services/IEmailQuotaService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index 99c25221..b7e6ad15 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -44,7 +44,7 @@ public interface IEmailQuotaService /// /// Sets the to the current date and - /// to the current email quota usage percentage then saves to the + /// to the current email quota usage percentage then saves it to the /// database. /// void SetQuotaOnEmailReminder(EmailQuota emailQuota); From aeffcb777a8ed93049fa67a62470f416d80eeaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:36:58 +0200 Subject: [PATCH 26/27] Renaming function --- .../Services/EmailQuotaService.cs | 2 +- .../Services/IEmailQuotaService.cs | 2 +- .../Services/QuotaManagingSmtpServiceDecorator.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs index fac73549..1228b449 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/EmailQuotaService.cs @@ -48,7 +48,7 @@ public EmailQuotaService( _userManager = userManager; } - public async Task> CollectUserEmailsForEmailReminderAsync() + public async Task> GetUserEmailsForEmailReminderAsync() { // Get users with site owner permission. var roles = await _roleService.GetRolesAsync(); diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs index b7e6ad15..4c40ee34 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaService.cs @@ -12,7 +12,7 @@ public interface IEmailQuotaService /// /// Collects the emails of the users who should receive the email reminder, based on the site owner permission. /// - Task> CollectUserEmailsForEmailReminderAsync(); + Task> GetUserEmailsForEmailReminderAsync(); /// /// Checks if the emails should be limited, depending on the default SMTP settings. diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs index bad5213c..7008084e 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/QuotaManagingSmtpServiceDecorator.cs @@ -65,7 +65,7 @@ private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota) var currentUsagePercentage = emailQuota.CurrentUsagePercentage(_emailQuotaService.GetEmailQuotaPerMonth()); if (!_emailQuotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return; - var siteOwnerEmails = (await _emailQuotaService.CollectUserEmailsForEmailReminderAsync()).ToList(); + var siteOwnerEmails = (await _emailQuotaService.GetUserEmailsForEmailReminderAsync()).ToList(); if (currentUsagePercentage >= 100) { SendQuotaEmail( From c5e3c0b448c491e20ed5d52d4a2f55c9bf0a64b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20N=C3=A9meth?= Date: Mon, 2 Oct 2023 11:39:10 +0200 Subject: [PATCH 27/27] Adding remarks --- .../Services/IEmailQuotaSubjectService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs index 04f429c9..7f6427f4 100644 --- a/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs +++ b/Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuotaSubjectService.cs @@ -5,6 +5,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services; /// /// Service for getting the subject of the email sent when the email quota is exceeded or when it's close to being exceeded. /// +/// Provides a way for overriding the subject texts. public interface IEmailQuotaSubjectService { ///