Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSOE-693: Display and send warnings also when 80 and 90% of the e-mail quota is reached #89

Merged
merged 28 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3956a32
Adding new logic for 80% and 90% reminders
wAsnk Sep 28, 2023
2f185a4
Adding percentage warnings
wAsnk Sep 28, 2023
eef620a
Fixing calculations
wAsnk Sep 28, 2023
6d1e19f
Adding new functionality UI test
wAsnk Sep 28, 2023
7f2d54f
Shouldn't do the rest if
wAsnk Sep 28, 2023
2d5fba9
Fixing code analyzer validations
wAsnk Sep 28, 2023
2d0b9b9
Breaking long lines
wAsnk Sep 29, 2023
a554740
Renaming class
wAsnk Sep 29, 2023
afcdef8
Moving function
wAsnk Sep 29, 2023
42c4343
Using generic text
wAsnk Sep 29, 2023
9b67d0a
Renaming files to more descriptive names
wAsnk Sep 29, 2023
6a67c4c
Adding email quota subject service
wAsnk Sep 29, 2023
81e7998
Renaming and code cleanups
wAsnk Sep 29, 2023
e2c195e
Cleanup and additional docs
wAsnk Sep 29, 2023
911c1a0
Merge remote-tracking branch 'origin/dev' into issue/OSOE-693
wAsnk Sep 29, 2023
dd16538
Should only check if necessary
wAsnk Sep 29, 2023
3e0b148
Code cleanup
wAsnk Sep 29, 2023
8d7c65d
Using same rounding as module
wAsnk Sep 29, 2023
e08b721
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuo…
wAsnk Oct 2, 2023
930ea80
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/DashboardQuo…
wAsnk Oct 2, 2023
4f55268
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailSetting…
wAsnk Oct 2, 2023
1b0e8da
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplat…
wAsnk Oct 2, 2023
65b7a37
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Views/EmailTemplat…
wAsnk Oct 2, 2023
301666c
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuo…
wAsnk Oct 2, 2023
602d93b
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuo…
wAsnk Oct 2, 2023
00046f5
Update Lombiq.Hosting.Tenants.EmailQuotaManagement/Services/IEmailQuo…
wAsnk Oct 2, 2023
aeffcb7
Renaming function
wAsnk Oct 2, 2023
c5e3c0b
Adding remarks
wAsnk Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 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(
Expand All @@ -21,26 +24,57 @@ 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();
var warningEmails = new List<int>();
for (int i = 0; i < maximumEmailQuota; i++)
{
await SendTestEmailAsync(context, SuccessfulSubject);
context.SuccessMessageExists();
CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, i + 1);
var warningLevel = Convert.ToInt32(Math.Round((double)(i + 1) / maximumEmailQuota * 100, 0));

CheckEmailsSentWarningMessage(context, exists: moduleShouldInterfere, maximumEmailQuota, 1);
if (!moduleShouldInterfere) continue;

await context.GoToDashboardAsync();
context.CheckExistence(By.XPath(DashboardWarning), exists: moduleShouldInterfere);
if (warningLevel >= 100)
{
await context.GoToDashboardAsync();
context.CheckExistence(By.XPath(DashboardExceededMessage), exists: true);
}
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: true);
if (!warningEmails.Contains(warningLevel))
{
warningEmails.Add(warningLevel);
}
}
}

await SendTestEmailAsync(context, UnSuccessfulSubject);
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),
exists: moduleShouldInterfere);
if (moduleShouldInterfere && warningMessageExists)
{
(context.GetAll(
ByHelper.SmtpInboxRow(WarningSubject)).Count == warningEmails.Count)
.ShouldBeTrue();
Piedone marked this conversation as resolved.
Show resolved Hide resolved
}

context.CheckExistence(ByHelper.SmtpInboxRow(UnSuccessfulSubject), exists: !moduleShouldInterfere);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -41,13 +41,25 @@ 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)
_emailQuotaService.ShouldLimitEmails())
{
var layout = await _layoutAccessor.GetLayoutAsync();
var contentZone = layout.Zones["Content"];
var currentEmailQuota = await _emailQuotaService.IsQuotaOverTheLimitAsync();

await contentZone.AddAsync(await _shapeFactory.CreateAsync("EmailQuotaError"), "0");
var currentUsagePercentage = currentEmailQuota.EmailQuota
.CurrentUsagePercentage(_emailQuotaService.GetEmailQuotaPerMonth());

if (currentUsagePercentage >= 80)
{
await contentZone.AddAsync(
await _shapeFactory.CreateAsync("DashboardQuotaMessage", new
{
currentEmailQuota.IsOverQuota,
UsagePercentage = currentUsagePercentage,
}),
"0");
}
}

await next();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -15,19 +13,16 @@ public class EmailSettingsQuotaFilter : IAsyncResultFilter
{
private readonly IShapeFactory _shapeFactory;
private readonly ILayoutAccessor _layoutAccessor;
private readonly IQuotaService _quotaService;
private readonly EmailQuotaOptions _emailQuotaOptions;
private readonly IEmailQuotaService _emailQuotaService;

public EmailSettingsQuotaFilter(
IShapeFactory shapeFactory,
ILayoutAccessor layoutAccessor,
IQuotaService quotaService,
IOptions<EmailQuotaOptions> emailQuotaOptions)
IEmailQuotaService emailQuotaService)
{
_shapeFactory = shapeFactory;
_layoutAccessor = layoutAccessor;
_quotaService = quotaService;
_emailQuotaOptions = emailQuotaOptions.Value;
_emailQuotaService = emailQuotaService;
}

public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
Expand All @@ -48,17 +43,17 @@ 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.GetOrCreateCurrentQuotaAsync();
await contentZone.AddAsync(
await _shapeFactory.CreateAsync("EmailSettingsQuota", new
await _shapeFactory.CreateAsync("EmailSettingsQuotaMessage", new
{
CurrentEmailCount = quota.CurrentEmailQuotaCount,
EmailQuota = _emailQuotaOptions.EmailQuotaPerMonth,
quota.CurrentEmailUsageCount,
EmailQuotaPerMonth = _emailQuotaService.GetEmailQuotaPerMonth(),
}),
"0");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ 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; }
}

public class EmailQuotaIndexProvider : IndexProvider<EmailQuota>
Expand All @@ -16,7 +17,8 @@ public override void Describe(DescribeContext<EmailQuota> context) =>
context.For<EmailQuotaIndex>()
.Map(emailQuota => new EmailQuotaIndex
{
CurrentEmailQuotaCount = emailQuota.CurrentEmailQuotaCount,
LastReminder = emailQuota.LastReminder,
CurrentEmailUsageCount = emailQuota.CurrentEmailUsageCount,
LastReminderUtc = emailQuota.LastReminderUtc,
LastReminderPercentage = emailQuota.LastReminderPercentage,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@ public class EmailQuotaMigrations : DataMigration
public int Create()
{
SchemaBuilder.CreateMapIndexTable<EmailQuotaIndex>(
table => table.Column<int>(nameof(EmailQuotaIndex.CurrentEmailQuotaCount))
.Column<DateTime>(nameof(EmailQuotaIndex.LastReminder)));
table => table.Column<int>(nameof(EmailQuotaIndex.CurrentEmailUsageCount))
.Column<DateTime>(nameof(EmailQuotaIndex.LastReminderUtc))
.Column<int>(nameof(EmailQuotaIndex.LastReminderPercentage)));

return 1;
return 2;
}

public int UpdateFrom1()
{
SchemaBuilder.AlterTable(nameof(EmailQuotaIndex), table => table
.AddColumn<int>(nameof(EmailQuotaIndex.LastReminderPercentage))
);

return 2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ 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; }

public int CurrentUsagePercentage(int emailQuotaPerMonth) =>
Convert.ToInt32(Math.Round((double)CurrentEmailUsageCount / emailQuotaPerMonth * 100, 0));
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public class EmailQuotaResetBackgroundTask : IBackgroundTask
{
public async Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken)
{
var quotaService = serviceProvider.GetRequiredService<IQuotaService>();
var currentQuota = await quotaService.GetCurrentQuotaAsync();
quotaService.ResetQuota(currentQuota);
var emailQuotaService = serviceProvider.GetRequiredService<IEmailQuotaService>();
var currentQuota = await emailQuotaService.GetOrCreateCurrentQuotaAsync();
emailQuotaService.ResetQuota(currentQuota);
}
}
Loading