diff --git a/Lombiq.Hosting.Tenants.Admin.Login/Lombiq.Hosting.Tenants.Admin.Login.csproj b/Lombiq.Hosting.Tenants.Admin.Login/Lombiq.Hosting.Tenants.Admin.Login.csproj index 6cf79790..5aa7f8d6 100644 --- a/Lombiq.Hosting.Tenants.Admin.Login/Lombiq.Hosting.Tenants.Admin.Login.csproj +++ b/Lombiq.Hosting.Tenants.Admin.Login/Lombiq.Hosting.Tenants.Admin.Login.csproj @@ -45,7 +45,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI.csproj b/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI.csproj index 9214240f..c9a0c567 100644 --- a/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI.csproj +++ b/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI/Lombiq.Hosting.Tenants.EnvironmentRobots.Tests.UI.csproj @@ -21,7 +21,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI.csproj b/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI.csproj index 9073abb5..21b52429 100644 --- a/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI.csproj +++ b/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI/Lombiq.Hosting.Tenants.FeaturesGuard.Tests.UI.csproj @@ -33,7 +33,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.FeaturesGuard/Lombiq.Hosting.Tenants.FeaturesGuard.csproj b/Lombiq.Hosting.Tenants.FeaturesGuard/Lombiq.Hosting.Tenants.FeaturesGuard.csproj index 30438fbb..b261ca10 100644 --- a/Lombiq.Hosting.Tenants.FeaturesGuard/Lombiq.Hosting.Tenants.FeaturesGuard.csproj +++ b/Lombiq.Hosting.Tenants.FeaturesGuard/Lombiq.Hosting.Tenants.FeaturesGuard.csproj @@ -47,8 +47,8 @@ - - + + diff --git a/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI.csproj b/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI.csproj index dd787698..5e6e8a45 100644 --- a/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI.csproj +++ b/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI/Lombiq.Hosting.Tenants.IdleTenantManagement.Tests.UI.csproj @@ -21,7 +21,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.Maintenance.Tests.UI/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.csproj b/Lombiq.Hosting.Tenants.Maintenance.Tests.UI/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.csproj index ab640ee5..26de00e1 100644 --- a/Lombiq.Hosting.Tenants.Maintenance.Tests.UI/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.csproj +++ b/Lombiq.Hosting.Tenants.Maintenance.Tests.UI/Lombiq.Hosting.Tenants.Maintenance.Tests.UI.csproj @@ -21,7 +21,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.Maintenance/Constants/FeatureNames.cs b/Lombiq.Hosting.Tenants.Maintenance/Constants/FeatureNames.cs index b53d3da2..3acc16e1 100644 --- a/Lombiq.Hosting.Tenants.Maintenance/Constants/FeatureNames.cs +++ b/Lombiq.Hosting.Tenants.Maintenance/Constants/FeatureNames.cs @@ -7,4 +7,5 @@ public static class FeatureNames public const string UpdateSiteUrl = Maintenance + "." + nameof(UpdateSiteUrl); public const string UpdateShellRequestUrls = Maintenance + "." + nameof(UpdateShellRequestUrls); public const string AddSiteOwnerPermissionToRole = Maintenance + "." + nameof(AddSiteOwnerPermissionToRole); + public const string RemoveUsers = Maintenance + "." + nameof(RemoveUsers); } diff --git a/Lombiq.Hosting.Tenants.Maintenance/Lombiq.Hosting.Tenants.Maintenance.csproj b/Lombiq.Hosting.Tenants.Maintenance/Lombiq.Hosting.Tenants.Maintenance.csproj index ef8f9c69..303ab779 100644 --- a/Lombiq.Hosting.Tenants.Maintenance/Lombiq.Hosting.Tenants.Maintenance.csproj +++ b/Lombiq.Hosting.Tenants.Maintenance/Lombiq.Hosting.Tenants.Maintenance.csproj @@ -28,6 +28,8 @@ + + @@ -46,7 +48,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceOptions.cs b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceOptions.cs new file mode 100644 index 00000000..f269ef53 --- /dev/null +++ b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceOptions.cs @@ -0,0 +1,7 @@ +namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.RemoveUsers; + +public class RemoveUsersMaintenanceOptions +{ + public bool IsEnabled { get; set; } + public string EmailDomain { get; set; } +} diff --git a/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceProvider.cs b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceProvider.cs new file mode 100644 index 00000000..61820da9 --- /dev/null +++ b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/RemoveUsersMaintenanceProvider.cs @@ -0,0 +1,45 @@ +using Lombiq.Hosting.Tenants.Maintenance.Extensions; +using Lombiq.Hosting.Tenants.Maintenance.Models; +using Lombiq.Hosting.Tenants.Maintenance.Services; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using OrchardCore.Users; +using OrchardCore.Users.Models; +using System; +using System.Linq; +using System.Threading.Tasks; +using YesSql; + +namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.RemoveUsers; + +public class RemoveUsersMaintenanceProvider : MaintenanceProviderBase +{ + private readonly IOptions _options; + private readonly ISession _session; + private readonly UserManager _userManager; + + public RemoveUsersMaintenanceProvider( + IOptions options, + ISession session, + UserManager userManager) + { + _options = options; + _session = session; + _userManager = userManager; + } + + public override Task ShouldExecuteAsync(MaintenanceTaskExecutionContext context) => + Task.FromResult( + _options.Value.IsEnabled && + !context.WasLatestExecutionSuccessful()); + + public override async Task ExecuteAsync(MaintenanceTaskExecutionContext context) + { + var users = await _session.Query().ListAsync(); + foreach (var user in users.Where(user => + user.Email.EndsWith($"@{_options.Value.EmailDomain}", StringComparison.InvariantCulture))) + { + await _userManager.DeleteAsync(user); + } + } +} diff --git a/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/Startup.cs b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/Startup.cs new file mode 100644 index 00000000..58fa4760 --- /dev/null +++ b/Lombiq.Hosting.Tenants.Maintenance/Maintenance/RemoveUsers/Startup.cs @@ -0,0 +1,27 @@ +using Lombiq.Hosting.Tenants.Maintenance.Constants; +using Lombiq.Hosting.Tenants.Maintenance.Services; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using OrchardCore.Environment.Shell.Configuration; +using OrchardCore.Modules; + +namespace Lombiq.Hosting.Tenants.Maintenance.Maintenance.RemoveUsers; + +[Feature(FeatureNames.RemoveUsers)] +public class Startup : StartupBase +{ + private readonly IShellConfiguration _shellConfiguration; + + public Startup(IShellConfiguration shellConfiguration) => + _shellConfiguration = shellConfiguration; + + public override void ConfigureServices(IServiceCollection services) + { + var options = new RemoveUsersMaintenanceOptions(); + var configSection = _shellConfiguration.GetSection("Lombiq_Hosting_Tenants_Maintenance:RemoveUsers"); + configSection.Bind(options); + services.Configure(configSection); + + services.AddScoped(); + } +} diff --git a/Lombiq.Hosting.Tenants.Maintenance/Manifest.cs b/Lombiq.Hosting.Tenants.Maintenance/Manifest.cs index 07119061..2b134e01 100644 --- a/Lombiq.Hosting.Tenants.Maintenance/Manifest.cs +++ b/Lombiq.Hosting.Tenants.Maintenance/Manifest.cs @@ -42,3 +42,12 @@ DefaultTenantOnly = true, Dependencies = new[] { Maintenance } )] + +[assembly: Feature( + Id = RemoveUsers, + Name = "Lombiq Hosting - Tenants Maintenance - Remove Users", + Description = "Removes users with the configured email domain.", + Category = "Maintenance", + DefaultTenantOnly = true, + Dependencies = new[] { Maintenance } +)] diff --git a/Lombiq.Hosting.Tenants.Maintenance/Readme.md b/Lombiq.Hosting.Tenants.Maintenance/Readme.md index 6d552793..983dc56d 100644 --- a/Lombiq.Hosting.Tenants.Maintenance/Readme.md +++ b/Lombiq.Hosting.Tenants.Maintenance/Readme.md @@ -94,3 +94,22 @@ The following configuration options are available to set the shell request URLs: ``` **NOTE**: The `{TenantName}` placeholder will be replaced with the actual tenant name automatically. + +### `Lombiq.Hosting.Tenants.Maintenance.RemoveUsers` + +It's a maintenance task that removes users from the database with the given email domain. It is available only for the default tenant. Useful if you have Azure AD enabled in your production environment and you want to reset staging to the production database. Then you would get "System.InvalidOperationException: Provider AzureAD is already linked for userName" error, so deleting those users will solve the error. + +The following configuration should be used to allow the maintenance to run: + +```json +{ + "OrchardCore": { + "Lombiq_Hosting_Tenants_Maintenance": { + "RemoveUsers": { + "IsEnabled": true, + "EmailDomain": "example.com" + } + } + } +} +``` diff --git a/Lombiq.Hosting.Tenants.Management/Lombiq.Hosting.Tenants.Management.csproj b/Lombiq.Hosting.Tenants.Management/Lombiq.Hosting.Tenants.Management.csproj index 12924868..f97aa793 100644 --- a/Lombiq.Hosting.Tenants.Management/Lombiq.Hosting.Tenants.Management.csproj +++ b/Lombiq.Hosting.Tenants.Management/Lombiq.Hosting.Tenants.Management.csproj @@ -45,7 +45,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI.csproj b/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI.csproj index 94b6ecd3..58f7bc9f 100644 --- a/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI.csproj +++ b/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI/Lombiq.Hosting.Tenants.MediaStorageManagement.Tests.UI.csproj @@ -33,7 +33,7 @@ - + diff --git a/Lombiq.Hosting.Tenants.MediaStorageManagement/Lombiq.Hosting.Tenants.MediaStorageManagement.csproj b/Lombiq.Hosting.Tenants.MediaStorageManagement/Lombiq.Hosting.Tenants.MediaStorageManagement.csproj index e6d3a4b2..335edbd9 100644 --- a/Lombiq.Hosting.Tenants.MediaStorageManagement/Lombiq.Hosting.Tenants.MediaStorageManagement.csproj +++ b/Lombiq.Hosting.Tenants.MediaStorageManagement/Lombiq.Hosting.Tenants.MediaStorageManagement.csproj @@ -46,7 +46,7 @@ - +