From cc079a8aa4d471470aef069dbe199aca5494704c Mon Sep 17 00:00:00 2001 From: rpaquay Date: Tue, 26 Jan 2010 01:08:58 +0000 Subject: [PATCH] Bug fix Re-activate the slug constraint for pages. Published pages now should get their friendly slug on the front-end. --HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045974 --- .../Orchard.Pages/Orchard.Pages.csproj | 1 + .../Orchard.Pages/Services/PageService.cs | 24 ++++----- .../Orchard.Pages/Services/SlugConstraint.cs | 54 ++++++++++++++++--- .../Services/SlugConstraintUpdator.cs | 29 ++++++++++ .../Packages/Orchard.Roles/Extension.cs | 13 +---- src/Orchard/Environment/DefaultOrchardHost.cs | 26 +++++++-- .../Extensions/HackInstallationGenerator.cs | 18 ++++++- .../Extensions/IExtensionManagerEvents.cs | 30 +++++++++++ src/Orchard/Tasks/BackgroundService.cs | 1 - src/Orchard/Tasks/SweepGenerator.cs | 2 +- 10 files changed, 158 insertions(+), 40 deletions(-) create mode 100644 src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraintUpdator.cs diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj b/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj index 17d448292..2b25a4849 100644 --- a/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj +++ b/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj @@ -88,6 +88,7 @@ Code + diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Services/PageService.cs b/src/Orchard.Web/Packages/Orchard.Pages/Services/PageService.cs index 98e55cc06..40129b6f2 100644 --- a/src/Orchard.Web/Packages/Orchard.Pages/Services/PageService.cs +++ b/src/Orchard.Web/Packages/Orchard.Pages/Services/PageService.cs @@ -1,20 +1,22 @@ using System; using System.Collections.Generic; using System.Linq; +using Orchard.ContentManagement.Records; using Orchard.Pages.Models; using Orchard.Core.Common.Records; using Orchard.ContentManagement; -using Orchard.Services; using Orchard.Tasks.Scheduling; namespace Orchard.Pages.Services { public class PageService : IPageService { private readonly IContentManager _contentManager; private readonly IPublishingTaskManager _publishingTaskManager; + private readonly ISlugConstraint _slugConstraint; - public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager) { + public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager, ISlugConstraint slugConstraint) { _contentManager = contentManager; _publishingTaskManager = publishingTaskManager; + _slugConstraint = slugConstraint; } public IEnumerable Get() { @@ -22,24 +24,16 @@ namespace Orchard.Pages.Services { } public IEnumerable Get(PageStatus status) { - IEnumerable contentItems; - switch (status) { case PageStatus.All: - contentItems = _contentManager.Query(VersionOptions.Latest, "page").List(); - break; + return _contentManager.Query(VersionOptions.Latest).List(); case PageStatus.Published: - contentItems = _contentManager.Query(VersionOptions.Published, "page").List(); - break; + return _contentManager.Query(VersionOptions.Published).List(); case PageStatus.Offline: - contentItems = _contentManager.Query(VersionOptions.Latest, "page").List().Where(ci => !ci.VersionRecord.Published); - break; + return _contentManager.Query(VersionOptions.Latest).Where(ci => !ci.ContentItemVersionRecord.Published).List(); default: - contentItems = new List().Cast(); - break; + return Enumerable.Empty(); } - - return contentItems.Select(ci => ci.As()); } public Page Get(int id) { @@ -79,6 +73,7 @@ namespace Orchard.Pages.Services { public void Publish(Page page) { _publishingTaskManager.DeleteTasks(page.ContentItem); _contentManager.Publish(page.ContentItem); + _slugConstraint.AddPublishedSlug(page.Slug); } public void Publish(Page page, DateTime scheduledPublishUtc) { @@ -87,6 +82,7 @@ namespace Orchard.Pages.Services { public void Unpublish(Page page) { _contentManager.Unpublish(page.ContentItem); + _slugConstraint.RemovePublishedSlug(page.Slug); } public DateTime? GetScheduledPublishUtc(Page page) { diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraint.cs b/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraint.cs index 6555fd40d..03c22ebaa 100644 --- a/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraint.cs +++ b/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraint.cs @@ -3,34 +3,72 @@ using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Routing; +using Orchard.Logging; namespace Orchard.Pages.Services { public interface ISlugConstraint : IRouteConstraint, ISingletonDependency { void SetCurrentlyPublishedSlugs(IEnumerable slugs); string LookupPublishedSlug(string slug); + void AddPublishedSlug(string slug); + void RemovePublishedSlug(string slug); } public class SlugConstraint : ISlugConstraint { + /// + /// Singleton object, per Orchard Shell instance. We need to protect concurrent access to the + /// dictionary. + /// + private readonly object _syncLock = new object(); private IDictionary _currentlyPublishedSlugs = new Dictionary(); + public SlugConstraint() { + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + public void SetCurrentlyPublishedSlugs(IEnumerable values) { - _currentlyPublishedSlugs = values - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToDictionary(value => value, StringComparer.OrdinalIgnoreCase); + // Make a copy to avoid performing potential lazy computation inside the lock + string[] valuesArray = values.ToArray(); + + lock (_syncLock) { + _currentlyPublishedSlugs = valuesArray + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToDictionary(value => value, StringComparer.OrdinalIgnoreCase); + } + + Logger.Debug("Publishing slugs: {0}", string.Join(", ", valuesArray)); } public string LookupPublishedSlug(string slug) { - string actual; - if (_currentlyPublishedSlugs.TryGetValue(slug, out actual)) - return actual; - return slug; + lock (_syncLock) { + string actual; + if (_currentlyPublishedSlugs.TryGetValue(slug, out actual)) + return actual; + return slug; + } + } + + public void AddPublishedSlug(string slug) { + lock (_syncLock) { + _currentlyPublishedSlugs.Add(slug, slug); + } + } + + public void RemovePublishedSlug(string slug) { + lock (_syncLock) { + _currentlyPublishedSlugs.Remove(slug); + } } public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { object value; if (values.TryGetValue(parameterName, out value)) { var parameterValue = Convert.ToString(value); - return _currentlyPublishedSlugs.ContainsKey(parameterValue); + + lock (_syncLock) { + return _currentlyPublishedSlugs.ContainsKey(parameterValue); + } } return false; } diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraintUpdator.cs b/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraintUpdator.cs new file mode 100644 index 000000000..1a3124d1a --- /dev/null +++ b/src/Orchard.Web/Packages/Orchard.Pages/Services/SlugConstraintUpdator.cs @@ -0,0 +1,29 @@ +using System.Linq; +using Orchard.Extensions; +using Orchard.Tasks; + +namespace Orchard.Pages.Services { + public class SlugConstraintUpdator : ExtensionManagerEvents, IBackgroundTask { + private readonly ISlugConstraint _slugConstraint; + private readonly IPageService _pageService; + + public SlugConstraintUpdator(ISlugConstraint slugConstraint, IPageService pageService) { + _slugConstraint = slugConstraint; + _pageService = pageService; + } + + public override void Activated(ExtensionEventContext context) { + if (context.Extension.Descriptor.Name == "Orchard.Pages") { + Refresh(); + } + } + + public void Sweep() { + Refresh(); + } + + private void Refresh() { + _slugConstraint.SetCurrentlyPublishedSlugs(_pageService.Get(PageStatus.Published).Select(page => page.Slug)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Packages/Orchard.Roles/Extension.cs b/src/Orchard.Web/Packages/Orchard.Roles/Extension.cs index c80acf19c..1c9ae3de4 100644 --- a/src/Orchard.Web/Packages/Orchard.Roles/Extension.cs +++ b/src/Orchard.Web/Packages/Orchard.Roles/Extension.cs @@ -7,7 +7,7 @@ using Orchard.Security.Permissions; namespace Orchard.Roles { [UsedImplicitly] - public class Extension : IExtensionManagerEvents { + public class Extension : ExtensionManagerEvents { private readonly IRoleService _roleService; private readonly IEnumerable _permissionProviders; @@ -18,10 +18,7 @@ namespace Orchard.Roles { _permissionProviders = permissionProviders; } - public void Enabling(ExtensionEventContext context) { - } - - public void Enabled(ExtensionEventContext context) { + public override void Enabled(ExtensionEventContext context) { // when another package is being enabled, locate matching permission providers var providersForEnabledPackage = _permissionProviders.Where(x => x.PackageName == context.Extension.Descriptor.Name); @@ -47,11 +44,5 @@ namespace Orchard.Roles { } } } - - public void Disabling(ExtensionEventContext context) { - } - - public void Disabled(ExtensionEventContext context) { - } } } diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 8d56768af..e6e109156 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -38,7 +38,8 @@ namespace Orchard.Environment { } protected virtual void Initialize() { - var shell = CreateShell(); + var shellContainer = CreateShellContainer(); + var shell = shellContainer.Resolve(); shell.Activate(); _current = shell; @@ -46,12 +47,19 @@ namespace Orchard.Environment { _controllerBuilder.SetControllerFactory(new OrchardControllerFactory()); ServiceLocator.SetLocator(t => _containerProvider.RequestContainer.Resolve(t)); - // fire off one-time install events on an alternate container + // Fire off one-time install events on an alternate container + HackInstallSimulation(); + + // Activate extensions inside shell container + HackSimulateExtensionActivation(shellContainer); + } + + private void HackInstallSimulation() { var tempContainer = CreateShellContainer(); var containerProvider = new FiniteContainerProvider(tempContainer); try { var requestContainer = containerProvider.RequestContainer; - + var hackInstallationGenerator = requestContainer.Resolve(); hackInstallationGenerator.GenerateInstallEvents(); } @@ -60,7 +68,19 @@ namespace Orchard.Environment { containerProvider.DisposeRequestContainer(); tempContainer.Dispose(); } + } + private void HackSimulateExtensionActivation(IContainer shellContainer) { + var containerProvider = new FiniteContainerProvider(shellContainer); + try { + var requestContainer = containerProvider.RequestContainer; + + var hackInstallationGenerator = requestContainer.Resolve(); + hackInstallationGenerator.GenerateActivateEvents(); + } + finally { + containerProvider.DisposeRequestContainer(); + } } protected virtual void EndRequest() { diff --git a/src/Orchard/Extensions/HackInstallationGenerator.cs b/src/Orchard/Extensions/HackInstallationGenerator.cs index adeb93017..3ae2e78f8 100644 --- a/src/Orchard/Extensions/HackInstallationGenerator.cs +++ b/src/Orchard/Extensions/HackInstallationGenerator.cs @@ -1,10 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Orchard.Logging; using Orchard.Utility; namespace Orchard.Extensions { public interface IHackInstallationGenerator : IDependency { void GenerateInstallEvents(); + void GenerateActivateEvents(); } public class HackInstallationGenerator : IHackInstallationGenerator { @@ -22,7 +24,6 @@ namespace Orchard.Extensions { public ILogger Logger { get; set; } public void GenerateInstallEvents() { - //TEMP: this is really part of the extension manager's job. an extension // install event is being simulated here on each web app startup var enabled = new List(); @@ -37,5 +38,18 @@ namespace Orchard.Extensions { _extensionEvents.Invoke(x => x.Enabled(context), Logger); } } + + public void GenerateActivateEvents() { + //TEMP: This is really part of the extension manager's job. + var extensions = _extensionManager.ActiveExtensions().ToReadOnlyCollection(); + foreach (var extension in extensions) { + var context = new ExtensionEventContext { + Extension = extension, + EnabledExtensions = extensions, + }; + _extensionEvents.Invoke(x => x.Activating(context), Logger); + _extensionEvents.Invoke(x => x.Activated(context), Logger); + } + } } } diff --git a/src/Orchard/Extensions/IExtensionManagerEvents.cs b/src/Orchard/Extensions/IExtensionManagerEvents.cs index 8d174e92f..bb7df714f 100644 --- a/src/Orchard/Extensions/IExtensionManagerEvents.cs +++ b/src/Orchard/Extensions/IExtensionManagerEvents.cs @@ -6,6 +6,36 @@ namespace Orchard.Extensions { void Enabled(ExtensionEventContext context); void Disabling(ExtensionEventContext context); void Disabled(ExtensionEventContext context); + void Activating(ExtensionEventContext context); + void Activated(ExtensionEventContext context); + void Deactivating(ExtensionEventContext context); + void Deactivated(ExtensionEventContext context); + } + + public abstract class ExtensionManagerEvents : IExtensionManagerEvents { + public virtual void Enabling(ExtensionEventContext context) { + } + + public virtual void Enabled(ExtensionEventContext context) { + } + + public virtual void Disabling(ExtensionEventContext context) { + } + + public virtual void Disabled(ExtensionEventContext context) { + } + + public virtual void Activating(ExtensionEventContext context) { + } + + public virtual void Activated(ExtensionEventContext context) { + } + + public virtual void Deactivating(ExtensionEventContext context) { + } + + public virtual void Deactivated(ExtensionEventContext context) { + } } public class ExtensionEventContext { diff --git a/src/Orchard/Tasks/BackgroundService.cs b/src/Orchard/Tasks/BackgroundService.cs index 03df61836..0267c44f2 100644 --- a/src/Orchard/Tasks/BackgroundService.cs +++ b/src/Orchard/Tasks/BackgroundService.cs @@ -23,5 +23,4 @@ namespace Orchard.Tasks { _tasks.Invoke(task => task.Sweep(), Logger); } } - } diff --git a/src/Orchard/Tasks/SweepGenerator.cs b/src/Orchard/Tasks/SweepGenerator.cs index 87e7cebf0..1326f05c9 100644 --- a/src/Orchard/Tasks/SweepGenerator.cs +++ b/src/Orchard/Tasks/SweepGenerator.cs @@ -14,7 +14,7 @@ namespace Orchard.Tasks { _timer = new Timer(); _timer.Elapsed += Elapsed; Logger = NullLogger.Instance; - Interval = TimeSpan.FromSeconds(30); + Interval = TimeSpan.FromMinutes(5); } public ILogger Logger { get; set; }