From 0e1cca0fce31195b638c2ee2e0ffceaeb0168d9a Mon Sep 17 00:00:00 2001 From: Lombiq Date: Mon, 30 Nov 2015 23:37:59 +0100 Subject: [PATCH] Improving how dependencies for themes are handled: enabling dependencies (modules) for themes too, handling this also when themes are just previewed and disabling themes when their dependencies are disabled. Fixes the tightly connected following issues: #4336, #5004, #4667 --- .../Controllers/AdminController.cs | 21 +++++++ .../Events/ThemeDisableEventHandler.cs | 61 +++++++++++++++++++ .../Orchard.Themes/Orchard.Themes.csproj | 1 + .../Orchard.Themes/Services/IThemeService.cs | 4 +- .../Orchard.Themes/Services/ThemeService.cs | 35 +++++++++-- 5 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Themes/Events/ThemeDisableEventHandler.cs diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Themes/Controllers/AdminController.cs index a3620d099..52ce4206c 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Themes/Controllers/AdminController.cs @@ -37,6 +37,8 @@ namespace Orchard.Themes.Controllers { private readonly IReportsCoordinator _reportsCoordinator; private readonly ShellSettings _shellSettings; + private const string AlreadyEnabledFeatures = "Orchard.Themes.AlreadyEnabledFeatures"; + public AdminController( IEnumerable extensionDisplayEventHandlers, IOrchardServices services, @@ -136,8 +138,11 @@ namespace Orchard.Themes.Controllers { Services.Notifier.Error(T("Theme {0} was not found", themeId)); } else { + var alreadyEnabledFeatures = GetEnabledFeatures(); _themeService.EnableThemeFeatures(themeId); _previewTheme.SetPreviewTheme(themeId); + alreadyEnabledFeatures.Except(new[] { themeId }); + TempData[AlreadyEnabledFeatures] = alreadyEnabledFeatures; } return this.RedirectLocal(returnUrl, "~/"); @@ -165,6 +170,18 @@ namespace Orchard.Themes.Controllers { if (!Services.Authorizer.Authorize(Permissions.ApplyTheme, T("Couldn't preview the current theme"))) return new HttpUnauthorizedResult(); + if (TempData.ContainsKey(AlreadyEnabledFeatures)) { + + var alreadyEnabledFeatures = TempData[AlreadyEnabledFeatures] as IEnumerable; + if (alreadyEnabledFeatures != null) { + var afterEnabledFeatures = GetEnabledFeatures(); + if (afterEnabledFeatures.Count() > alreadyEnabledFeatures.Count()) { + var disableFeatures = afterEnabledFeatures.Except(alreadyEnabledFeatures); + _themeService.DisablePreviewFeatures(disableFeatures); + } + } + } + _previewTheme.SetPreviewTheme(null); return RedirectToAction("Index"); @@ -256,5 +273,9 @@ namespace Orchard.Themes.Controllers { return string.IsNullOrEmpty(value); } } + + public IEnumerable GetEnabledFeatures() { + return _featureManager.GetEnabledFeatures().Select(f => f.Id); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Events/ThemeDisableEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Themes/Events/ThemeDisableEventHandler.cs new file mode 100644 index 000000000..380f8b144 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Themes/Events/ThemeDisableEventHandler.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Orchard.Environment; +using Orchard.Environment.Extensions.Models; +using Orchard.Environment.Features; +using Orchard.Localization; +using Orchard.Themes.Services; +using Orchard.UI.Notify; + +namespace Orchard.Themes.Events { + public class ThemeDisableEventHandler : IFeatureEventHandler { + private readonly IFeatureManager _featureManager; + private readonly ISiteThemeService _siteThemeService; + private readonly INotifier _notifier; + + public ThemeDisableEventHandler( + IFeatureManager featureManager, + ISiteThemeService siteThemeService, + INotifier notifier) { + _featureManager = featureManager; + _siteThemeService = siteThemeService; + _notifier = notifier; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public void Installing(Feature feature) { + } + + public void Installed(Feature feature) { + } + + public void Enabling(Feature feature) { + } + + public void Enabled(Feature feature) { + } + + public void Disabling(Feature feature) { + } + + public void Disabled(Feature feature) { + var currentTheme = _siteThemeService.GetCurrentThemeName(); + if (feature.Descriptor.Name == currentTheme) { + _siteThemeService.SetSiteTheme(null); + + // Notifications don't work in feature events. See: https://github.com/OrchardCMS/Orchard/issues/6106 + _notifier.Warning(T("The current theme was disabled, because one of its dependencies was disabled.")); + } + } + + public void Uninstalling(Feature feature) { + } + + public void Uninstalled(Feature feature) { + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Orchard.Themes.csproj b/src/Orchard.Web/Modules/Orchard.Themes/Orchard.Themes.csproj index 7c65cffd9..cd9986edc 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Orchard.Themes.csproj +++ b/src/Orchard.Web/Modules/Orchard.Themes/Orchard.Themes.csproj @@ -66,6 +66,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Services/IThemeService.cs b/src/Orchard.Web/Modules/Orchard.Themes/Services/IThemeService.cs index f9fa25535..e5f8a2229 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Services/IThemeService.cs +++ b/src/Orchard.Web/Modules/Orchard.Themes/Services/IThemeService.cs @@ -1,9 +1,11 @@ -using Orchard.Environment.Extensions.Models; +using System.Collections.Generic; +using Orchard.Environment.Extensions.Models; namespace Orchard.Themes.Services { public interface IThemeService : IDependency { void DisableThemeFeatures(string themeName); void EnableThemeFeatures(string themeName); bool IsRecentlyInstalled(ExtensionDescriptor module); + void DisablePreviewFeatures(IEnumerable features); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Services/ThemeService.cs b/src/Orchard.Web/Modules/Orchard.Themes/Services/ThemeService.cs index 8d58faa10..a5928e5c9 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Services/ThemeService.cs +++ b/src/Orchard.Web/Modules/Orchard.Themes/Services/ThemeService.cs @@ -20,6 +20,7 @@ namespace Orchard.Themes.Services { private readonly IEnumerable _themeSelectors; private readonly IVirtualPathProvider _virtualPathProvider; private readonly ICacheManager _cacheManager; + private readonly ISiteThemeService _siteThemeService; public ThemeService( IOrchardServices orchardServices, @@ -27,7 +28,8 @@ namespace Orchard.Themes.Services { IFeatureManager featureManager, IEnumerable themeSelectors, IVirtualPathProvider virtualPathProvider, - ICacheManager cacheManager) { + ICacheManager cacheManager, + ISiteThemeService siteThemeService) { Services = orchardServices; @@ -36,6 +38,7 @@ namespace Orchard.Themes.Services { _themeSelectors = themeSelectors; _virtualPathProvider = virtualPathProvider; _cacheManager = cacheManager; + _siteThemeService = siteThemeService; if (_featureManager.FeatureDependencyNotification == null) { _featureManager.FeatureDependencyNotification = GenerateWarning; @@ -64,8 +67,16 @@ namespace Orchard.Themes.Services { : null; } - while (themes.Count > 0) - _featureManager.DisableFeatures(new[] { themes.Dequeue() }); + var currentTheme = _siteThemeService.GetCurrentThemeName(); + + while (themes.Count > 0) { + var themeId = themes.Dequeue(); + + // Not disabling base theme if it's the current theme. + if (themeId != currentTheme) { + _featureManager.DisableFeatures(new[] { themeId }); + } + } } public void EnableThemeFeatures(string themeName) { @@ -81,8 +92,15 @@ namespace Orchard.Themes.Services { : null; } - while (themes.Count > 0) - _featureManager.EnableFeatures(new[] {themes.Pop()}); + while (themes.Count > 0) { + var themeId = themes.Pop(); + foreach (var featureId in _featureManager.EnableFeatures(new[] { themeId }, true)) { + if (themeId != featureId) { + var featureName = _featureManager.GetAvailableFeatures().First(f => f.Id.Equals(featureId, StringComparison.OrdinalIgnoreCase)).Name; + Services.Notifier.Information(T("{0} was enabled", featureName)); + } + } + } } public ExtensionDescriptor GetRequestTheme(RequestContext requestContext) { @@ -174,5 +192,12 @@ namespace Orchard.Themes.Services { : "{0}, "), fn).ToString()).ToArray()) : featuresInQuestion.First())); } + + public void DisablePreviewFeatures(IEnumerable features) { + foreach (var featureId in _featureManager.DisableFeatures(features,true)) { + var featureName = _featureManager.GetAvailableFeatures().First(f => f.Id.Equals(featureId, StringComparison.OrdinalIgnoreCase)).Name; + Services.Notifier.Information(T("{0} was disabled", featureName)); + } + } } }