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-548: Upgrade to Orchard Core 1.6 in Hosting-Tenants #55

Merged
merged 51 commits into from
Jun 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8bc572b
Upgrading to OC 1.6.
Psichorex Apr 25, 2023
a8eb49c
Giving workaround for Orchard related problem.
Psichorex Apr 28, 2023
902ae2f
Optimizing foreach loop.
Psichorex May 2, 2023
abfa52d
Using deferredTask to prevent recursive runs.
Psichorex May 11, 2023
51edc12
Adjusting handler to handle every possible case.
Psichorex May 15, 2023
a976c9d
Encapsulating whole method in a defferredTask.
Psichorex May 17, 2023
428c37e
DRYing the handler.
Psichorex May 17, 2023
73f0cb4
Optimizing handler.
Psichorex May 17, 2023
47e98e5
Removing empty line.
Psichorex May 17, 2023
5a6e309
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Psichorex May 17, 2023
c482b98
Updating packages.
Psichorex May 17, 2023
96a3b30
Adding comments and structuring.
Psichorex May 17, 2023
4b959bd
Adding comment to DisableConditionallyEnabledFeaturesAsync.
Psichorex May 17, 2023
0a88d60
Generalized remark
Piedone May 17, 2023
d9a519d
Optimizing handler and refactoring.
Psichorex May 18, 2023
3ad6851
Merge branch 'issue/OSOE-548' of https://github.com/Lombiq/Hosting-Te…
Psichorex May 18, 2023
ba11aa8
Adding period.
Psichorex May 18, 2023
d3a2051
Adding parameter name.
Psichorex May 18, 2023
97f31af
Adding service to Deferred Task.
Psichorex May 18, 2023
ac98adc
Adding checks and Exceptions.
Psichorex May 18, 2023
cb7a796
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Psichorex May 18, 2023
9b7a9bd
Code styling
Piedone May 18, 2023
6dc78ee
Conventional method name
Piedone May 18, 2023
5dfef24
Punctuation
Piedone May 18, 2023
e577208
Fixing variable usage.
Psichorex May 19, 2023
4624660
Consolidating HL.Common package.
Psichorex May 20, 2023
ddf1f4e
Upgrading Lombiq.ChartJs.Tests.UI package.
Psichorex May 20, 2023
4d48731
Updating to latest Lombiq alpha releases.
Psichorex May 22, 2023
6edeb65
Removing mistakenly included "v" from versions.
Psichorex May 22, 2023
8947a01
Updating to latest Lombiq.Tests.UI alpha release.
Psichorex May 22, 2023
691d54d
Removing interface name from method declarations.
Psichorex May 22, 2023
a0fa3e7
Merge branch 'dev' into issue/OSOE-548
Psichorex May 24, 2023
4084db8
Upgrading packages in Lombiq.Hosting.Tenants.EnvironmentRobots.
Psichorex May 24, 2023
153dc18
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Psichorex May 24, 2023
ae8c2e4
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Psichorex May 29, 2023
db022b6
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Psichorex Jun 6, 2023
61e337d
Upgrading Lombiq.HelpfulLibraries.* package reference version
dministro Jun 9, 2023
7cd9f86
Merge branch 'dev' of https://github.com/Lombiq/Hosting-Tenants into …
dministro Jun 10, 2023
01fffcc
Merge branch 'issue/OSOE-548' of https://github.com/Lombiq/Hosting-Te…
dministro Jun 10, 2023
e59ee8d
Fixing analyzer violation
dministro Jun 10, 2023
8523609
Merge pull request #70 from Lombiq/issue/OSOE-641
Piedone Jun 10, 2023
7727f2d
Fixing local boolean to prevent multiple runs.
Psichorex Jun 11, 2023
14e36aa
Moving bool value changed out of deferredTask.
Psichorex Jun 12, 2023
070548d
Renaming variable
Piedone Jun 12, 2023
1f23c93
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Piedone Jun 14, 2023
581877d
Updating Lombiq.HelpfulLibraries NuGet reference to latest alpha
Piedone Jun 16, 2023
92d37e5
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
sarahelsaig Jun 16, 2023
a68fd1a
Merge remote-tracking branch 'origin/dev' into issue/OSOE-548
Piedone Jun 18, 2023
f6f5550
Updating newly added OC packages to 1.6
Piedone Jun 18, 2023
b50508c
Updating Lombiq NuGet references
Piedone Jun 18, 2023
c605bc8
Updating Lombiq NuGet references to release versions
Piedone Jun 18, 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 @@ -34,18 +34,18 @@
</ItemGroup>

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

<ItemGroup Condition="'$(NuGetBuild)' != 'true'">
<ProjectReference Include="..\..\..\Libraries\Lombiq.HelpfulLibraries\Lombiq.HelpfulLibraries.OrchardCore\Lombiq.HelpfulLibraries.OrchardCore.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' == 'true'">
<PackageReference Include="Lombiq.HelpfulLibraries.OrchardCore" Version="5.2.0" />
<PackageReference Include="Lombiq.HelpfulLibraries.OrchardCore" Version="6.0.0" />
</ItemGroup>

</Project>
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="6.1.0" />
<PackageReference Include="Lombiq.Tests.UI" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="1.5.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="1.5.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="1.5.0" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="1.6.0" />
<PackageReference Include="OrchardCore.Module.Targets" Version="1.6.0" />
<PackageReference Include="OrchardCore.ResourceManagement" Version="1.6.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private static async Task SetUpNewTenantAndGoToFeaturesListAsync(
{
await context.SignInDirectlyAsync();

await context.CreateAndSwitchToTenantManuallyAsync(tenantName, tenantUrlPrefix, string.Empty, "features guard");
await context.CreateAndSwitchToTenantManuallyAsync(tenantName, tenantUrlPrefix, string.Empty, "Features Guard");

await context.GoToSetupPageAndSetupOrchardCoreAsync(
new OrchardCoreSetupParameters(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
<None Remove="node_modules\**" />
<None Remove="Tests\**" />
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' != 'true'">
<ProjectReference Include="..\..\..\..\test\Lombiq.UITestingToolbox\Lombiq.Tests.UI\Lombiq.Tests.UI.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' == 'true'">
<PackageReference Include="Lombiq.Tests.UI" Version="6.1.0" />
<PackageReference Include="Lombiq.Tests.UI" Version="7.0.0" />
</ItemGroup>

</Project>
248 changes: 112 additions & 136 deletions Lombiq.Hosting.Tenants.FeaturesGuard/Handlers/FeaturesEventHandler.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using Lombiq.Hosting.Tenants.FeaturesGuard.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OrchardCore.Environment.Extensions.Features;
using OrchardCore.Environment.Shell;
using OrchardCore.Environment.Shell.Descriptor;
using OrchardCore.Environment.Shell.Descriptor.Models;
using OrchardCore.Environment.Shell.Scope;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -14,168 +13,145 @@ namespace Lombiq.Hosting.Tenants.FeaturesGuard.Handlers;

public sealed class FeaturesEventHandler : IFeatureEventHandler
{
private readonly IShellFeaturesManager _shellFeaturesManager;
private readonly IOptions<ConditionallyEnabledFeaturesOptions> _conditionallyEnabledFeaturesOptions;
private readonly ShellSettings _shellSettings;
private readonly IShellDescriptorManager _shellDescriptorManager;

public FeaturesEventHandler(
IShellFeaturesManager shellFeaturesManager,
IOptions<ConditionallyEnabledFeaturesOptions> conditionallyEnabledFeaturesOptions,
ShellSettings shellSettings,
IConfiguration configuration,
IShellDescriptorManager shellDescriptorManager)
{
_shellFeaturesManager = shellFeaturesManager;
_conditionallyEnabledFeaturesOptions = conditionallyEnabledFeaturesOptions;
_shellSettings = shellSettings;
_shellDescriptorManager = shellDescriptorManager;
}

Task IFeatureEventHandler.InstallingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.InstalledAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.EnablingAsync(IFeatureInfo feature) => Task.CompletedTask;

Task IFeatureEventHandler.EnabledAsync(IFeatureInfo feature) => EnableConditionallyEnabledFeaturesAsync(feature);

Task IFeatureEventHandler.DisablingAsync(IFeatureInfo feature) => Task.CompletedTask;

async Task IFeatureEventHandler.DisabledAsync(IFeatureInfo feature)
{
await KeepConditionallyEnabledFeaturesEnabledAsync(feature);
await DisableConditionallyEnabledFeaturesAsync(feature);
}

Task IFeatureEventHandler.UninstallingAsync(IFeatureInfo feature) => Task.CompletedTask; // #spell-check-ignore-line
private bool _deferredTaskTriggered;

Task IFeatureEventHandler.UninstalledAsync(IFeatureInfo feature) => Task.CompletedTask;
public Task InstallingAsync(IFeatureInfo feature) => Task.CompletedTask;

/// <summary>
/// Enables conditional features (key) if one of their corresponding condition features (value) was enabled.
/// </summary>
/// <param name="featureInfo">The feature that was just enabled.</param>
public async Task EnableConditionallyEnabledFeaturesAsync(IFeatureInfo featureInfo)
{
if (_shellSettings.IsDefaultShell() ||
_conditionallyEnabledFeaturesOptions.Value.EnableFeatureIfOtherFeatureIsEnabled is not { } conditionallyEnabledFeatures)
{
return;
}

var allConditionFeatureIds = new List<string>();
foreach (var conditionFeatureIds in conditionallyEnabledFeatures.Values)
{
allConditionFeatureIds.AddRange(conditionFeatureIds);
}
public Task InstalledAsync(IFeatureInfo feature) => Task.CompletedTask;

if (!allConditionFeatureIds.Contains(featureInfo.Id))
{
return;
}
public Task EnablingAsync(IFeatureInfo feature) => Task.CompletedTask;

// Enable conditional features if they are not already enabled.
var allFeatures = await _shellFeaturesManager.GetAvailableFeaturesAsync();
public Task EnabledAsync(IFeatureInfo feature) => HandleConditionallyEnabledFeaturesAsync();

var conditionalFeatureIds = conditionallyEnabledFeatures
.Where(keyValuePair => keyValuePair.Value.Contains(featureInfo.Id))
.Select(keyValuePair => keyValuePair.Key)
.ToList();
public Task DisablingAsync(IFeatureInfo feature) => Task.CompletedTask;

// During setup, Shell Descriptor can become out of sync with the DB when it comes to enabled features,
// but it's more accurate than IShellDescriptorManager's methods.
var shellDescriptor = await _shellDescriptorManager.GetShellDescriptorAsync();
public Task DisabledAsync(IFeatureInfo feature) => HandleConditionallyEnabledFeaturesAsync();

// If Shell Descriptor's Features already contains a feature that is found in conditionalFeatures, remove it
// from the list. Handle multiple conditional features as well.
var featuresToEnable = allFeatures.Where(feature =>
conditionalFeatureIds.Contains(feature.Id) && !shellDescriptor.Features.Contains(new ShellFeature(feature.Id)));
public Task UninstallingAsync(IFeatureInfo feature) => Task.CompletedTask; // #spell-check-ignore-line

await _shellFeaturesManager.EnableFeaturesAsync(featuresToEnable, force: true);
}
public Task UninstalledAsync(IFeatureInfo feature) => Task.CompletedTask;

/// <summary>
/// When a conditional feature (key) is disabled, keeps the conditional feature enabled if any of the corresponding
/// condition features (value) are enabled.
/// Enables or disables conditional features depending on ConditionallyEnabledFeaturesOptions.
/// Prevents disabling features that should be enabled according to their conditions.
/// </summary>
/// <param name="featureInfo">The feature that was just disabled.</param>
public async Task KeepConditionallyEnabledFeaturesEnabledAsync(IFeatureInfo featureInfo)
private Task HandleConditionallyEnabledFeaturesAsync()
Piedone marked this conversation as resolved.
Show resolved Hide resolved
{
if (_shellSettings.IsDefaultShell() ||
_conditionallyEnabledFeaturesOptions.Value.EnableFeatureIfOtherFeatureIsEnabled is not { } conditionallyEnabledFeatures)
if (_deferredTaskTriggered)
{
return;
return Task.CompletedTask;
}

if (!conditionallyEnabledFeatures.ContainsKey(featureInfo.Id))
{
return;
}

// Re-enable conditional feature if any its condition features are enabled.
var allFeatures = await _shellFeaturesManager.GetAvailableFeaturesAsync();
var conditionFeatureIds = conditionallyEnabledFeatures[featureInfo.Id];
_deferredTaskTriggered = true;

var currentlyEnabledFeatures = await _shellFeaturesManager.GetEnabledFeaturesAsync();
var conditionFeatures = allFeatures.Where(feature => conditionFeatureIds.Contains(feature.Id));

var currentlyEnabledConditionFeatures = currentlyEnabledFeatures.Intersect(conditionFeatures);
if (currentlyEnabledConditionFeatures.Any())
ShellScope.AddDeferredTask(async scope =>
Piedone marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

@jtkech jtkech May 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just before, try to use and check a _deferredTask boolean as suggested.

It prevents many deferred tasks from being triggered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtkech I tried the _deferredTaskExecuted boolean like you have suggested but there is a catch for me with it.
So it basically prevents the handler to run multiple times that is understandable but this for me kills the functionality of the half feature.
For example OrchardCore.Facebook and OrchardCore.Twitter will be enabled if Lombiq.UIKit is enabled.
But after this point if I disable Lombiq.UIKit the other 2 features will remain enabled. Also If I want to turn off Facebook I can turn it off eventhough it should stay enabled because Lombiq.UIKit is still enabled.
But the handler is not running once more because of the boolean set to true.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This delegate handles any number of features to be enabled/disabled, no? So it shouldn't require running more than once for an updated shell.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Piedone The problem if it runs once than as I described

Yes, using a local bool (to reduce the deferred tasks) works well on my side (if the handler is a scoped service), if @Psichorex has an use case that doesn't work we would need to understand what happens.

if (_deferredTask)
{
    return Task.CompletedTask;
}

_deferredTask = true;

ShellScope.AddDeferredTask(async scope =>

@jtkech Here is my repro if I use _deferredTask boolean:

  1. Create a new tenant from the default tenant
  2. Setup the new tenant
  3. When clicking setup the Handler will run and it will enable all conditional features and _deferredTask will be true.
  4. Go to the new Tenant admin and try to disable a condition feature or a conditional feature
  5. The handler for me never runs again thus I can disable a conditional feature eventhough it's condition is still on and it should be kept enabled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the repro, I will try it this night.

Can you show me the code that registers the handler and defines the _deferredTask variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jtkech Sending you what you need.

image
image
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this is preventing the handler to ever be executed again.
So basically this will execute only once when the tenant is being initialized.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay just retried, I can't repro, it works well on my side, _deferredTask is false again when the handler is resolved from another scope. Did you retry it with the new code where states are retrieved and all the logic done in the deferred task?

I used the same code unless that I always configure the options by code (one conditional/condition) and that I always register the handler by code, looks like you are doing it through a module/feature startup.

Okay, just retried by using a separate OC.FeaturesGuard that I included in the setup recipe, all still works fine, the only difference is that I still always config my testing options by code (not from the configuration) in the module startup.

As a side note, not tried but I think you could get rid of the ConditionallyEnabledFeatures config section and then bind directly on ConditionallyEnabledFeaturesOptions, but as you want.

{
var conditionalFeature = allFeatures.Where(feature => feature.Id == featureInfo.Id);
await _shellFeaturesManager.EnableFeaturesAsync(conditionalFeature);
}
if (scope.ShellContext.Settings.IsDefaultShell())
{
return;
}

var shellFeaturesManager = scope
.ServiceProvider
.GetRequiredService<IShellFeaturesManager>();

var conditionallyEnabledFeaturesOptions = scope
.ServiceProvider
.GetRequiredService<IOptions<ConditionallyEnabledFeaturesOptions>>()
.Value
.EnableFeatureIfOtherFeatureIsEnabled;

var enabledFeatures = (await shellFeaturesManager.GetEnabledFeaturesAsync())
.ToHashSet();

var enabledFeaturesIds = enabledFeatures
.Select(feature => feature.Id)
.ToHashSet();

if (!TryGetFeaturesToBeEnabledAndDisabled(
conditionallyEnabledFeaturesOptions,
enabledFeaturesIds,
out var featuresToEnableIds,
out var featuresToDisableIds))
{
return;
}

var availableFeatures = await shellFeaturesManager.GetAvailableFeaturesAsync();

var featuresToEnable = availableFeatures
.Where(feature => featuresToEnableIds.Contains(feature.Id))
.ToList();

if (featuresToEnable.Exists(feature => feature.DefaultTenantOnly || feature.EnabledByDependencyOnly))
{
throw new InvalidOperationException("'DefaultTenantOnly' feature can't be enabled by FeaturesGuard.");
}

var featuresToDisable = enabledFeatures
.Where(feature => featuresToDisableIds.Contains(feature.Id))
.ToList();

if (featuresToDisable.Exists(feature => feature.IsAlwaysEnabled || feature.EnabledByDependencyOnly))
{
throw new InvalidOperationException("'IsAlwaysEnabled' feature can't be disabled by FeaturesGuard.");
}

if (!featuresToEnable.Any() && !featuresToDisable.Any())
{
return;
}

await shellFeaturesManager.UpdateFeaturesAsync(featuresToDisable, featuresToEnable, force: true);
});

return Task.CompletedTask;
}

/// <summary>
/// When a condition feature (value) is disabled, disables the corresponding conditional features (key) if all of
/// their condition features are disabled.
/// Extracts the feature ids from ConditionallyEnabledFeaturesOptions and separates them into
/// <paramref name="featuresToEnable"></paramref> and <paramref name="featuresToDisable"></paramref> hash sets
/// and compares them to <paramref name="enabledFeatureIds"/> collection to determine which features need to be
/// enabled or disabled.
/// </summary>
/// <param name="featureInfo">The feature that was just disabled.</param>
public async Task DisableConditionallyEnabledFeaturesAsync(IFeatureInfo featureInfo)
/// <returns>A boolean value whether ConditionallyEnabledFeaturesOptions is populated or not.
/// Also produces <paramref name="featuresToEnable"/> and <paramref name="featuresToDisable"/>.
/// </returns>
private static bool TryGetFeaturesToBeEnabledAndDisabled(
Piedone marked this conversation as resolved.
Show resolved Hide resolved
IDictionary<string, IEnumerable<string>> conditionallyEnabledFeatures,
IReadOnlySet<string> enabledFeatureIds,
out HashSet<string> featuresToEnable,
out HashSet<string> featuresToDisable)
{
if (_shellSettings.IsDefaultShell() ||
_conditionallyEnabledFeaturesOptions.Value.EnableFeatureIfOtherFeatureIsEnabled is not { } conditionallyEnabledFeatures)
if (!conditionallyEnabledFeatures.Any())
{
return;
featuresToEnable = null;
featuresToDisable = null;
return false;
}

var allConditionFeatureIds = new List<string>();
foreach (var conditionFeatureIdList in conditionallyEnabledFeatures.Values)
{
allConditionFeatureIds.AddRange(conditionFeatureIdList);
}
var featuresToEnableIds = new HashSet<string>();
var featuresToDisableIds = new HashSet<string>();

if (!allConditionFeatureIds.Contains(featureInfo.Id))
foreach (var condition in conditionallyEnabledFeatures)
{
return;
var hasConditional = enabledFeatureIds.Contains(condition.Key);
var hasCondition = enabledFeatureIds.Intersect(condition.Value).Any();

if (hasCondition && !hasConditional)
{
featuresToEnableIds.Add(condition.Key);
}

if (!hasCondition && hasConditional)
{
featuresToDisableIds.Add(condition.Key);
}
}

// If current feature is one of the condition features, disable its corresponding conditional features if they
// are not already disabled.
var allFeatures = await _shellFeaturesManager.GetAvailableFeaturesAsync();

var conditionalFeatureIds = new List<string>();
var conditionFeatureIds = new List<string>();
foreach (var keyValuePair in conditionallyEnabledFeatures.Where(keyValuePair => keyValuePair.Value.Contains(featureInfo.Id)))
{
conditionalFeatureIds.Add(keyValuePair.Key);
conditionFeatureIds.AddRange(keyValuePair.Value);
}
featuresToEnable = featuresToEnableIds;
featuresToDisable = featuresToDisableIds;

var currentlyEnabledFeatures = await _shellFeaturesManager.GetEnabledFeaturesAsync();
var conditionFeatures = allFeatures.Where(feature => conditionFeatureIds.Contains(feature.Id));

// Only disable conditional feature if none of its condition features are enabled.
var currentlyEnabledConditionFeatures = currentlyEnabledFeatures.Intersect(conditionFeatures);
if (!currentlyEnabledConditionFeatures.Any())
{
// Handle multiple conditional features as well.
var conditionalFeatures = allFeatures.Where(feature => conditionalFeatureIds.Contains(feature.Id));
var currentlyEnabledConditionalFeatures = currentlyEnabledFeatures.Intersect(conditionalFeatures);

await _shellFeaturesManager.DisableFeaturesAsync(currentlyEnabledConditionalFeatures);
}
return featuresToEnableIds.Any() || featuresToDisableIds.Any();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
</ItemGroup>

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

<ItemGroup Condition="'$(NuGetBuild)' != 'true'">
Expand All @@ -47,8 +47,8 @@
</ItemGroup>

<ItemGroup Condition="'$(NuGetBuild)' == 'true'">
<PackageReference Include="Lombiq.HelpfulLibraries.OrchardCore" Version="5.2.0" />
<PackageReference Include="Lombiq.HelpfulLibraries.Common" Version="5.2.0" />
<PackageReference Include="Lombiq.HelpfulLibraries.OrchardCore" Version="6.0.0" />
<PackageReference Include="Lombiq.HelpfulLibraries.Common" Version="6.0.0" />
</ItemGroup>

</Project>
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="6.1.0" />
<PackageReference Include="Lombiq.Tests.UI" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading