Skip to content

Commit

Permalink
Merge pull request #135 from Lombiq/issue/OSOE-903
Browse files Browse the repository at this point in the history
OSOE-903: Update to Orchard Core 2.1.0, `AddAdministratorRoleToUsersWithRole` maintenance instead of `AddSiteOwnerPermissionToRole`
  • Loading branch information
sarahelsaig authored Dec 4, 2024
2 parents 9878510 + d5d94e4 commit f5016b2
Show file tree
Hide file tree
Showing 35 changed files with 294 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.0.0" />
<PackageReference Include="OrchardCore.Tenants" Version="2.0.0" />
<PackageReference Include="OrchardCore.Users" Version="2.0.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.1.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.1.0" />
<PackageReference Include="OrchardCore.Tenants" Version="2.1.0" />
<PackageReference Include="OrchardCore.Users" Version="2.1.0" />
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' != 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Lombiq.Hosting.Tenants.Admin.Login.Permissions;
public sealed class TenantAdminPermissions : AdminPermissionBase
{
public static readonly Permission LoginAsAdmin =
new(nameof(LoginAsAdmin), "Able to login as an admin to any tenant from the Default tenant.");
new(nameof(LoginAsAdmin), "Able to login as an admin to any tenant from the Default tenant.", isSecurityCritical: true);

protected override IEnumerable<Permission> AdminPermissions => [LoginAsAdmin];
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' == 'true'">
<PackageReference Include="Lombiq.Tests.UI" Version="11.0.0" />
<PackageReference Include="Lombiq.Tests.UI" Version="11.1.1-alpha.1.osoe-903" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Lombiq.Hosting.Tenants.EmailQuotaManagement.Services.EmailQuotaService.#ctor(YesSql.ISession,Microsoft.Extensions.Options.IOptions{Lombiq.Hosting.Tenants.EmailQuotaManagement.Models.EmailQuotaOptions},Microsoft.Extensions.Options.IOptions{OrchardCore.Email.DefaultSmtpOptions},Microsoft.Extensions.Options.IOptions{OrchardCore.Email.SmtpOptions},OrchardCore.Modules.IClock,OrchardCore.Security.Services.IRoleService,Microsoft.AspNetCore.Identity.UserManager{OrchardCore.Users.IUser})</Target>
<Left>lib/net8.0/Lombiq.Hosting.Tenants.EmailQuotaManagement.dll</Left>
<Right>lib/net8.0/Lombiq.Hosting.Tenants.EmailQuotaManagement.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
</Suppressions>
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Admin" Version="2.0.0" />
<PackageReference Include="OrchardCore.Email" Version="2.0.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.0.0" />
<PackageReference Include="OrchardCore.AdminDashboard" Version="2.0.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.Email.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore.Admin" Version="2.1.0" />
<PackageReference Include="OrchardCore.Email" Version="2.1.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.1.0" />
<PackageReference Include="OrchardCore.AdminDashboard" Version="2.1.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.1.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="2.1.0" />
<PackageReference Include="OrchardCore.Email.Abstractions" Version="2.1.0" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.1.0" />
<PackageReference Include="Scrutor" Version="4.2.2" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion Lombiq.Hosting.Tenants.EmailQuotaManagement/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This module currently contains one feature:

With this module, you can specify how much space would you like to limit each tenant's maximum email quota. The default is 1000 per month. You can change this value in the _appsettings.json_ file or with an environment variable. When the quota is reached the email won't be sent and also the following will happen:

- An email will be sent to the tenant's users who has Site Owner permission.
- An email will be sent to the tenant's users with the Administrator role.
- A warning message will be shown that the limit has been reached on the admin dashboard.

Also a warning message is always shown with the current email quota status on the email settings page when the same host is used as the predefined one from the environment variables or from the _appsettings.json_ file.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
using Lombiq.Hosting.Tenants.EmailQuotaManagement.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using OrchardCore;
using OrchardCore.Email;
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;

Expand All @@ -26,7 +23,6 @@ public class EmailQuotaService : IEmailQuotaService
private readonly DefaultSmtpOptions _defaultSmtpOptions;
private readonly SmtpOptions _smtpOptions;
private readonly IClock _clock;
private readonly IRoleService _roleService;
private readonly UserManager<IUser> _userManager;

public EmailQuotaService(
Expand All @@ -35,33 +31,20 @@ public EmailQuotaService(
IOptions<DefaultSmtpOptions> defaultSmtpOptions,
IOptions<SmtpOptions> smtpOptions,
IClock clock,
IRoleService roleService,
UserManager<IUser> userManager)
{
_session = session;
_emailQuotaOptions = emailQuotaOptions.Value;
_defaultSmtpOptions = defaultSmtpOptions.Value;
_smtpOptions = smtpOptions.Value;
_clock = clock;
_roleService = roleService;
_userManager = userManager;
}

public async Task<IEnumerable<string>> GetUserEmailsForEmailReminderAsync()
{
// 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<IUser>();
foreach (var role in siteOwnerRoles)
{
siteOwners.AddRange(await _userManager.GetUsersInRoleAsync(role.RoleName));
}

return siteOwners.Select(user => (user as User)?.Email);
var administratorUsers = await _userManager.GetUsersInRoleAsync(OrchardCoreConstants.Roles.Administrator);
return administratorUsers.Select(user => (user as User)?.Email);
}

public bool ShouldLimitEmails() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Lombiq.Hosting.Tenants.EmailQuotaManagement.Services;
public interface IEmailQuotaService
{
/// <summary>
/// Collects the emails of the users who should receive the email reminder, based on the site owner permission.
/// Collects the emails of the users who should receive the email reminder, based on the Administrator role.
/// </summary>
Task<IEnumerable<string>> GetUserEmailsForEmailReminderAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ private async Task SendAlertEmailIfNecessaryAsync(EmailQuota emailQuota)
var currentUsagePercentage = emailQuota.CurrentUsagePercentage(_emailQuotaService.GetEmailQuotaPerMonth());
if (!_emailQuotaService.ShouldSendReminderEmail(emailQuota, currentUsagePercentage)) return;

var siteOwnerEmails = (await _emailQuotaService.GetUserEmailsForEmailReminderAsync()).ToList();
var administratorEmails = (await _emailQuotaService.GetUserEmailsForEmailReminderAsync()).ToList();
if (currentUsagePercentage >= 100)
{
await SendQuotaEmailAsync(
emailQuota,
siteOwnerEmails,
administratorEmails,
"EmailQuotaExceededError",
_emailQuotaSubjectService.GetExceededEmailSubject(),
currentUsagePercentage);
Expand All @@ -76,15 +76,15 @@ await SendQuotaEmailAsync(

await SendQuotaEmailAsync(
emailQuota,
siteOwnerEmails,
administratorEmails,
$"EmailQuotaWarning",
_emailQuotaSubjectService.GetWarningEmailSubject(currentUsagePercentage),
currentUsagePercentage);
}

private Task SendQuotaEmailAsync(
EmailQuota emailQuota,
IEnumerable<string> siteOwnerEmails,
IEnumerable<string> administratorEmails,
string emailTemplateName,
string subject,
int percentage)
Expand All @@ -94,11 +94,11 @@ private Task SendQuotaEmailAsync(
IsHtmlBody = true,
Subject = subject,
};
foreach (var siteOwnerEmail in siteOwnerEmails)
foreach (var administratorEmail in administratorEmails)
{
ShellScope.AddDeferredTask(async _ =>
{
emailMessage.To = siteOwnerEmail;
emailMessage.To = administratorEmail;
emailMessage.Body = await _emailTemplateService.RenderEmailTemplateAsync(emailTemplateName, new
{
HostName = _shellSettings.Name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.0.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.1.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.1.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="2.1.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.0.0" />
<PackageReference Include="OrchardCore.ContentManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.0.0" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.1.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.1.0" />
<PackageReference Include="OrchardCore.ContentManagement" Version="2.1.0" />
<PackageReference Include="OrchardCore.ContentTypes.Abstractions" Version="2.1.0" />
<PackageReference Include="OrchardCore.DisplayManagement" Version="2.1.0" />
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' != 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ public static void ConfigureIdleTenantManagementTestSettings(this OrchardCoreUIT
"1")
.AddWithValue(
"Logging:LogLevel:Lombiq.Hosting.Tenants.IdleTenantManagement.Services.IdleShutdownService",
"Information");
"Information")
.AddWithValue(
"OrchardCore:OrchardCore_BackgroundService:PollingTime",
"00:00:05")
.AddWithValue(
"OrchardCore:OrchardCore_BackgroundService:MinimumIdleTime",
"00:00:01");

return Task.CompletedTask;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Lombiq.Tests.UI.Extensions;
using Lombiq.Tests.UI.Helpers;
using Lombiq.Tests.UI.Pages;
using Lombiq.Tests.UI.Services;
using System;
using System.Linq;
using System.Threading.Tasks;
using static Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI.Constants.IdleTenantData;

Expand All @@ -26,19 +29,23 @@ await context.GoToSetupPageAndSetupOrchardCoreAsync(
RunSetupOnCurrentPage = true,
});

// We are letting the site to sit idle for more than two minutes so that the tenant can be shut down by the
// background task.
// Once https://github.com/OrchardCMS/OrchardCore/issues/17031 is fixed, we can configure a short background
// task polling and idle time instead.
await Task.Delay(129420);
// Due to the background ask scheduling configuration in ConfigureIdleTenantManagementTestSettings(), the
// background task should run within not much more than a minute (background tasks are run with a frequency of
// at least a minute, due to the limitation of cron expressions). Polling for it here.
await Task.Delay(TimeSpan.FromMinutes(1));
await ReliabilityHelper.DoWithRetriesOrFailAsync(
async () =>
{
var logEntries = await context.Application.GetLogEntriesFromAllLogsAsync();
return logEntries.Any(logEntry =>
logEntry.Message == $"Shutting down tenant \"{IdleTenantName}\" because of idle timeout.");
},
TimeSpan.FromMinutes(1),
TimeSpan.FromSeconds(1));

// If we can access the admin menu after the tenant shut down that means the new shell was created and it is
// working as intended.
await context.SignInDirectlyAsync();
await context.GoToDashboardAsync();

// Make sure the shutdown message is in the logs.
await context.Application.LogsShouldContainAsync(logEntry =>
logEntry.Message == $"Shutting down tenant \"{IdleTenantName}\" because of idle timeout.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' == 'true'">
<PackageReference Include="Lombiq.Tests.UI" Version="11.1.1-alpha.0.osoe-402" />
<PackageReference Include="Lombiq.Tests.UI" Version="11.1.1-alpha.1.osoe-903" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
<PackageReference Include="OrchardCore.Abstractions" Version="2.0.0" />
<PackageReference Include="OrchardCore" Version="2.0.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.0.0" />
<PackageReference Include="OrchardCore.Abstractions" Version="2.1.0" />
<PackageReference Include="OrchardCore" Version="2.1.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="2.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Lombiq.Hosting.Tenants.Maintenance.Tests.UI.Extensions.MaintenanceExtensions</Target>
<Left>lib/net8.0/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.dll</Left>
<Right>lib/net8.0/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Lombiq.Hosting.Tenants.Maintenance.Tests.UI.Extensions.TestCaseUITestContextExtensions.TestSiteOwnerPermissionToRoleMaintenanceExecutionAsync(Lombiq.Tests.UI.Services.UITestContext)</Target>
<Left>lib/net8.0/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.dll</Left>
<Right>lib/net8.0/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
</Suppressions>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Lombiq.Hosting.Tenants.Maintenance.Tests.UI.Extensions;

public static class MaintenanceExtensions
public static class MaintenanceOrchardCoreUITestExecutorConfigurationExtensions
{
public static void SetUpdateSiteUrlMaintenanceConfiguration(
this OrchardCoreUITestExecutorConfiguration configuration) => configuration.OrchardCoreConfiguration.BeforeAppStart +=
Expand All @@ -20,16 +20,16 @@ public static void SetUpdateSiteUrlMaintenanceConfiguration(
return Task.CompletedTask;
};

public static void SetAddSiteOwnerPermissionToRoleMaintenanceConfiguration(
public static void SetAddAdministratorRoleToUsersWithRoleConfiguration(
this OrchardCoreUITestExecutorConfiguration configuration) => configuration.OrchardCoreConfiguration.BeforeAppStart +=
(_, argumentsBuilder) =>
{
argumentsBuilder
.AddWithValue(
"OrchardCore:Lombiq_Hosting_Tenants_Maintenance:AddSiteOwnerPermissionToRole:IsEnabled",
"OrchardCore:Lombiq_Hosting_Tenants_Maintenance:AddAdministratorRoleToUsersWithRole:IsEnabled",
value: true)
.AddWithValue(
"OrchardCore:Lombiq_Hosting_Tenants_Maintenance:AddSiteOwnerPermissionToRole:Role",
"OrchardCore:Lombiq_Hosting_Tenants_Maintenance:AddAdministratorRoleToUsersWithRole:Role",
value: "Editor");

return Task.CompletedTask;
Expand Down
Loading

0 comments on commit f5016b2

Please sign in to comment.