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
This commit is contained in:
rpaquay
2010-01-26 01:08:58 +00:00
parent c026cb9e34
commit cc079a8aa4
10 changed files with 158 additions and 40 deletions

View File

@@ -88,6 +88,7 @@
<Compile Include="Services\SlugConstraint.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Services\SlugConstraintUpdator.cs" />
<Compile Include="ViewModels\PageCreateViewModel.cs" />
<Compile Include="ViewModels\PageEditViewModel.cs" />
<Compile Include="ViewModels\PagesViewModel.cs" />

View File

@@ -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<Page> Get() {
@@ -22,24 +24,16 @@ namespace Orchard.Pages.Services {
}
public IEnumerable<Page> Get(PageStatus status) {
IEnumerable<ContentItem> contentItems;
switch (status) {
case PageStatus.All:
contentItems = _contentManager.Query(VersionOptions.Latest, "page").List();
break;
return _contentManager.Query<Page>(VersionOptions.Latest).List();
case PageStatus.Published:
contentItems = _contentManager.Query(VersionOptions.Published, "page").List();
break;
return _contentManager.Query<Page>(VersionOptions.Published).List();
case PageStatus.Offline:
contentItems = _contentManager.Query(VersionOptions.Latest, "page").List().Where(ci => !ci.VersionRecord.Published);
break;
return _contentManager.Query<Page>(VersionOptions.Latest).Where<ContentPartVersionRecord>(ci => !ci.ContentItemVersionRecord.Published).List();
default:
contentItems = new List<Page>().Cast<ContentItem>();
break;
return Enumerable.Empty<Page>();
}
return contentItems.Select(ci => ci.As<Page>());
}
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) {

View File

@@ -3,35 +3,73 @@ 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<string> slugs);
string LookupPublishedSlug(string slug);
void AddPublishedSlug(string slug);
void RemovePublishedSlug(string slug);
}
public class SlugConstraint : ISlugConstraint {
/// <summary>
/// Singleton object, per Orchard Shell instance. We need to protect concurrent access to the
/// dictionary.
/// </summary>
private readonly object _syncLock = new object();
private IDictionary<string, string> _currentlyPublishedSlugs = new Dictionary<string, string>();
public SlugConstraint() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SetCurrentlyPublishedSlugs(IEnumerable<string> values) {
_currentlyPublishedSlugs = values
// 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) {
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);
lock (_syncLock) {
return _currentlyPublishedSlugs.ContainsKey(parameterValue);
}
}
return false;
}
}

View File

@@ -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));
}
}
}

View File

@@ -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<IPermissionProvider> _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) {
}
}
}

View File

@@ -38,7 +38,8 @@ namespace Orchard.Environment {
}
protected virtual void Initialize() {
var shell = CreateShell();
var shellContainer = CreateShellContainer();
var shell = shellContainer.Resolve<IOrchardShell>();
shell.Activate();
_current = shell;
@@ -46,7 +47,14 @@ 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 {
@@ -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<IHackInstallationGenerator>();
hackInstallationGenerator.GenerateActivateEvents();
}
finally {
containerProvider.DisposeRequestContainer();
}
}
protected virtual void EndRequest() {

View File

@@ -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<ExtensionEntry>();
@@ -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);
}
}
}
}

View File

@@ -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 {

View File

@@ -23,5 +23,4 @@ namespace Orchard.Tasks {
_tasks.Invoke(task => task.Sweep(), Logger);
}
}
}

View File

@@ -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; }