From e41e43bda4498ccb10d0abcd754836ccdc0990a5 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Tue, 7 Dec 2010 20:35:58 -0800 Subject: [PATCH 1/6] Simplifying code, and making more efficient too --HG-- branch : dev --- src/Orchard/Environment/Extensions/IExtensionManager.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Orchard/Environment/Extensions/IExtensionManager.cs b/src/Orchard/Environment/Extensions/IExtensionManager.cs index 723a82cd0..b79f0b95c 100644 --- a/src/Orchard/Environment/Extensions/IExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/IExtensionManager.cs @@ -15,13 +15,7 @@ namespace Orchard.Environment.Extensions { public static class ExtensionManagerExtensions { public static IEnumerable EnabledFeatures(this IExtensionManager extensionManager, ShellDescriptor descriptor) { - return extensionManager.AvailableExtensions() - .SelectMany(extensionDescriptor => extensionDescriptor.Features) - .Where(featureDescriptor => IsFeatureEnabledInDescriptor(featureDescriptor, descriptor)); - } - - private static bool IsFeatureEnabledInDescriptor(FeatureDescriptor featureDescriptor, ShellDescriptor shellDescriptor) { - return shellDescriptor.Features.Any(shellDescriptorFeature => shellDescriptorFeature.Name == featureDescriptor.Id); + return extensionManager.AvailableFeatures().Where(fd => descriptor.Features.Any(sf => sf.Name == fd.Id)); } } } From ab3d0a2636a2339c6f0127fd1af09f5c411a81ce Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Wed, 8 Dec 2010 14:27:50 -0800 Subject: [PATCH 2/6] Fix computed set of views paths to allow themes in the admin When looking for ViewPath to activate, the order should be: 1. Current active theme 2. Base themes of the current theme (in "base" order). Note that "base themes" for "TheAdmin" theme means all enabled themes 3. Modules which have at least one active feature, in feature dependency order Work Item: 16654 --HG-- branch : dev --- .../ThemeAwareness/ThemeAwareViewEngine.cs | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs b/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs index c7484e827..f2c14c544 100644 --- a/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs +++ b/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs @@ -5,6 +5,7 @@ using System.Web.Mvc; using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; +using Orchard.Logging; namespace Orchard.Mvc.ViewEngines.ThemeAwareness { public interface IThemeAwareViewEngine : IDependency { @@ -31,8 +32,12 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { _configuredEnginesCache = configuredEnginesCache; _extensionManager = extensionManager; _shellDescriptor = shellDescriptor; + + Logger = NullLogger.Instance; } + public ILogger Logger { get; set; } + public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache, bool useDeepPaths) { var engines = _nullEngines; @@ -71,21 +76,78 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { private IViewEngine DeepEngines(ExtensionDescriptor theme) { return _configuredEnginesCache.BindDeepEngines(theme.Id, () => { + // The order for searching for views is: + // 1. Current "theme" + // 2. Base themes of the current theme (in "base" order) + // 3. Active features from modules in dependency order + var engines = Enumerable.Empty(); var themeLocation = theme.Location + "/" + theme.Id; + // 1. current theme var themeParams = new CreateThemeViewEngineParams { VirtualPath = themeLocation }; engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams))); - var activeFeatures = _extensionManager.AvailableFeatures().Where(fd => _shellDescriptor.Features.Any(sdf => sdf.Name == fd.Id)); - var activeModuleLocations = activeFeatures.Select(fd => fd.Extension.Location + "/" + fd.Extension.Id).Distinct(); - var moduleParams = new CreateModulesViewEngineParams { VirtualPaths = activeModuleLocations }; + // 2. Base themes of the current theme (in "base" order) + var baseThemes = GetBaseThemes(theme); + + // 3. Active features from modules in dependency order + var enabledModules = _extensionManager.EnabledFeatures(_shellDescriptor) + .Reverse() // reverse from (C <= B <= A) to (A => B => C) + .Where(fd => !DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType)/*core + modules*/); + + var allLocations = baseThemes.Concat(enabledModules) + .Select(fd => fd.Extension.Location + "/" + fd.Extension.Id) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + var moduleParams = new CreateModulesViewEngineParams { VirtualPaths = allLocations }; engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateModulesViewEngine(moduleParams))); return new ViewEngineCollectionWrapper(engines); }); } + private IEnumerable GetBaseThemes(ExtensionDescriptor themeExtension) { + if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase)) { + // Special case: conceptually, the base themes of "TheAdmin" is the list of all + // enabled themes. This is so that any enabled theme can have controller/action/views + // in the Admin of the site. + return _extensionManager + .EnabledFeatures(_shellDescriptor) + .Reverse() // reverse from (C <= B <= A) to (A => B => C) + .Where(fd => DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType)); + } + else { + var availableFeatures = _extensionManager.AvailableFeatures(); + var list = new List(); + while(true) { + if (themeExtension == null) + break; + + if (String.IsNullOrEmpty(themeExtension.BaseTheme)) + break; + + var baseFeature = availableFeatures.FirstOrDefault(fd => fd.Id == themeExtension.BaseTheme); + if (baseFeature == null) { + Logger.Error("Base theme '{0}' of theme '{1}' not found in list of features", themeExtension.BaseTheme, themeExtension.Id); + break; + } + + // Protect against potential infinite loop + if (list.Contains(baseFeature)) { + Logger.Error("Base theme '{0}' of theme '{1}' ignored, as it seems there is recursion in base themes", themeExtension.BaseTheme, themeExtension.Id); + break; + } + + list.Add(baseFeature); + + themeExtension = baseFeature.Extension; + } + return list; + } + } + public void ReleaseView(ControllerContext controllerContext, IView view) { throw new NotImplementedException(); } From a81d4c0821452189406f3a74b1e8432550d9a1b9 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Wed, 8 Dec 2010 14:44:55 -0800 Subject: [PATCH 3/6] Removing incorrect definition of extension type There is no such thing as a "Core" extension type. "Theme" and "Module" are the only valid extension types. --HG-- branch : dev --- src/Orchard.Specs/Bindings/OrchardSiteFactory.cs | 6 +++--- src/Orchard.Specs/Bindings/WebAppHosting.cs | 6 +++--- .../Environment/Extensions/Models/DefaultExtensionTypes.cs | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs b/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs index a702b1d20..889a47292 100644 --- a/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs +++ b/src/Orchard.Specs/Bindings/OrchardSiteFactory.cs @@ -21,9 +21,9 @@ namespace Orchard.Specs.Bindings { webApp.GivenIHaveACleanSiteWith( virtualDirectory, TableData( - new { extension = DefaultExtensionTypes.Module, names = "Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce" }, - new { extension = DefaultExtensionTypes.Core, names = "Common, Dashboard, Feeds, HomePage, Navigation, Contents, Routable, Scheduling, Settings, Shapes, XmlRpc" }, - new { extension = DefaultExtensionTypes.Theme, names = "SafeMode, TheAdmin, TheThemeMachine" })); + new { extension = "Module", names = "Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce" }, + new { extension = "Core", names = "Common, Dashboard, Feeds, HomePage, Navigation, Contents, Routable, Scheduling, Settings, Shapes, XmlRpc" }, + new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" })); webApp.WhenIGoTo("Setup"); diff --git a/src/Orchard.Specs/Bindings/WebAppHosting.cs b/src/Orchard.Specs/Bindings/WebAppHosting.cs index 7d3d839fc..7648b2e9d 100644 --- a/src/Orchard.Specs/Bindings/WebAppHosting.cs +++ b/src/Orchard.Specs/Bindings/WebAppHosting.cs @@ -140,13 +140,13 @@ namespace Orchard.Specs.Bindings { foreach (var row in table.Rows) { foreach (var name in row["names"].Split(',').Select(x => x.Trim())) { switch (row["extension"]) { - case DefaultExtensionTypes.Core: + case "Core": GivenIHaveCore(name); break; - case DefaultExtensionTypes.Module: + case "Module": GivenIHaveModule(name); break; - case DefaultExtensionTypes.Theme: + case "Theme": GivenIHaveTheme(name); break; default: diff --git a/src/Orchard/Environment/Extensions/Models/DefaultExtensionTypes.cs b/src/Orchard/Environment/Extensions/Models/DefaultExtensionTypes.cs index 607fe8fcf..372cd2d77 100644 --- a/src/Orchard/Environment/Extensions/Models/DefaultExtensionTypes.cs +++ b/src/Orchard/Environment/Extensions/Models/DefaultExtensionTypes.cs @@ -4,7 +4,6 @@ namespace Orchard.Environment.Extensions.Models { public static class DefaultExtensionTypes { public const string Module = "Module"; public const string Theme = "Theme"; - public const string Core = "Core"; public static bool IsModule(string extensionType) { return string.Equals(extensionType, Module, StringComparison.OrdinalIgnoreCase); From ff6c5f3edc14f65f3a71767855f0138ee8724d04 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Wed, 8 Dec 2010 15:40:15 -0800 Subject: [PATCH 4/6] Make the engine view discovery more correct For themes, the pattern is slighty different than for modules, Also, we need to interleave the different views engine in between themes and base themes, so that overrides between Razor and WebForms work as excpected. --HG-- branch : dev --- .../ThemeAwareness/ThemeAwareViewEngine.cs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs b/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs index f2c14c544..55ae0988a 100644 --- a/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs +++ b/src/Orchard/Mvc/ViewEngines/ThemeAwareness/ThemeAwareViewEngine.cs @@ -82,21 +82,18 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { // 3. Active features from modules in dependency order var engines = Enumerable.Empty(); - var themeLocation = theme.Location + "/" + theme.Id; - // 1. current theme - var themeParams = new CreateThemeViewEngineParams { VirtualPath = themeLocation }; - engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams))); + engines = engines.Concat(CreateThemeViewEngines(theme)); // 2. Base themes of the current theme (in "base" order) - var baseThemes = GetBaseThemes(theme); + engines = GetBaseThemes(theme).Aggregate(engines, (current, baseTheme) => current.Concat(CreateThemeViewEngines(baseTheme))); // 3. Active features from modules in dependency order var enabledModules = _extensionManager.EnabledFeatures(_shellDescriptor) .Reverse() // reverse from (C <= B <= A) to (A => B => C) - .Where(fd => !DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType)/*core + modules*/); + .Where(fd => DefaultExtensionTypes.IsModule(fd.Extension.ExtensionType)); - var allLocations = baseThemes.Concat(enabledModules) + var allLocations = enabledModules.Concat(enabledModules) .Select(fd => fd.Extension.Location + "/" + fd.Extension.Id) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); @@ -108,7 +105,13 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { }); } - private IEnumerable GetBaseThemes(ExtensionDescriptor themeExtension) { + private IEnumerable CreateThemeViewEngines(ExtensionDescriptor theme) { + var themeLocation = theme.Location + "/" + theme.Id; + var themeParams = new CreateThemeViewEngineParams {VirtualPath = themeLocation}; + return _viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams)); + } + + private IEnumerable GetBaseThemes(ExtensionDescriptor themeExtension) { if (themeExtension.Id.Equals("TheAdmin", StringComparison.OrdinalIgnoreCase)) { // Special case: conceptually, the base themes of "TheAdmin" is the list of all // enabled themes. This is so that any enabled theme can have controller/action/views @@ -116,11 +119,12 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { return _extensionManager .EnabledFeatures(_shellDescriptor) .Reverse() // reverse from (C <= B <= A) to (A => B => C) - .Where(fd => DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType)); + .Select(fd => fd.Extension) + .Where(fd => DefaultExtensionTypes.IsTheme(fd.ExtensionType)); } else { var availableFeatures = _extensionManager.AvailableFeatures(); - var list = new List(); + var list = new List(); while(true) { if (themeExtension == null) break; @@ -135,12 +139,12 @@ namespace Orchard.Mvc.ViewEngines.ThemeAwareness { } // Protect against potential infinite loop - if (list.Contains(baseFeature)) { + if (list.Contains(baseFeature.Extension)) { Logger.Error("Base theme '{0}' of theme '{1}' ignored, as it seems there is recursion in base themes", themeExtension.BaseTheme, themeExtension.Id); break; } - list.Add(baseFeature); + list.Add(baseFeature.Extension); themeExtension = baseFeature.Extension; } From c57a3ab642a29579b95bea159ebd86d66ad25ed9 Mon Sep 17 00:00:00 2001 From: Andre Rodrigues Date: Wed, 8 Dec 2010 18:17:55 -0800 Subject: [PATCH 5/6] #16756: Adding binding redirect for MVC from 1.0 to 3.0 --HG-- branch : dev --- src/Orchard.Web/Web.config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Web.config b/src/Orchard.Web/Web.config index 653221a2a..68c8c0377 100644 --- a/src/Orchard.Web/Web.config +++ b/src/Orchard.Web/Web.config @@ -16,7 +16,7 @@
- + @@ -143,7 +143,8 @@ - + + From acb4ccf530604e6a54e5c209a1467aacb3cb1c8a Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 8 Dec 2010 18:28:41 -0800 Subject: [PATCH 6/6] Fixing Enable/Disable display in Features view --HG-- branch : dev --- .../Modules/Orchard.Modules/Views/Admin/Features.cshtml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml b/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml index 0b5ff95c8..3f252a303 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Modules/Views/Admin/Features.cshtml @@ -25,7 +25,7 @@ } //temporarily "disable" actions on core features - var showActions = categoryName.ToString() != "Core"; + bool showActions;
  • @categoryName

      @{ @@ -46,9 +46,7 @@ select (from f in Model.Features where f.Descriptor.Id == d select f).SingleOrDefault()).Where(f => f != null).OrderBy(f => f.Descriptor.Name); var missingDependencies = feature.Descriptor.Dependencies .Where(d => !Model.Features.Any(f => f.Descriptor.Id == d)); - if (showActions) { - showActions = missingDependencies.Count() == 0; - } + showActions = categoryName.ToString() != "Core" && missingDependencies.Count() == 0;