Skip to content

Commit

Permalink
Merge pull request #89 from Lombiq/issue/OSOE-693
Browse files Browse the repository at this point in the history
OSOE-693: Display and send warnings also when 80 and 90% of the e-mail quota is reached
  • Loading branch information
Piedone authored Oct 2, 2023
2 parents 8456b59 + c5e3c0b commit 2174a36
Show file tree
Hide file tree
Showing 25 changed files with 501 additions and 329 deletions.
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();
}

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

0 comments on commit 2174a36

Please sign in to comment.