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"> <Compile Include="Services\SlugConstraint.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Services\SlugConstraintUpdator.cs" />
<Compile Include="ViewModels\PageCreateViewModel.cs" /> <Compile Include="ViewModels\PageCreateViewModel.cs" />
<Compile Include="ViewModels\PageEditViewModel.cs" /> <Compile Include="ViewModels\PageEditViewModel.cs" />
<Compile Include="ViewModels\PagesViewModel.cs" /> <Compile Include="ViewModels\PagesViewModel.cs" />

View File

@@ -1,20 +1,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Orchard.ContentManagement.Records;
using Orchard.Pages.Models; using Orchard.Pages.Models;
using Orchard.Core.Common.Records; using Orchard.Core.Common.Records;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Services;
using Orchard.Tasks.Scheduling; using Orchard.Tasks.Scheduling;
namespace Orchard.Pages.Services { namespace Orchard.Pages.Services {
public class PageService : IPageService { public class PageService : IPageService {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly IPublishingTaskManager _publishingTaskManager; private readonly IPublishingTaskManager _publishingTaskManager;
private readonly ISlugConstraint _slugConstraint;
public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager) { public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager, ISlugConstraint slugConstraint) {
_contentManager = contentManager; _contentManager = contentManager;
_publishingTaskManager = publishingTaskManager; _publishingTaskManager = publishingTaskManager;
_slugConstraint = slugConstraint;
} }
public IEnumerable<Page> Get() { public IEnumerable<Page> Get() {
@@ -22,24 +24,16 @@ namespace Orchard.Pages.Services {
} }
public IEnumerable<Page> Get(PageStatus status) { public IEnumerable<Page> Get(PageStatus status) {
IEnumerable<ContentItem> contentItems;
switch (status) { switch (status) {
case PageStatus.All: case PageStatus.All:
contentItems = _contentManager.Query(VersionOptions.Latest, "page").List(); return _contentManager.Query<Page>(VersionOptions.Latest).List();
break;
case PageStatus.Published: case PageStatus.Published:
contentItems = _contentManager.Query(VersionOptions.Published, "page").List(); return _contentManager.Query<Page>(VersionOptions.Published).List();
break;
case PageStatus.Offline: case PageStatus.Offline:
contentItems = _contentManager.Query(VersionOptions.Latest, "page").List().Where(ci => !ci.VersionRecord.Published); return _contentManager.Query<Page>(VersionOptions.Latest).Where<ContentPartVersionRecord>(ci => !ci.ContentItemVersionRecord.Published).List();
break;
default: default:
contentItems = new List<Page>().Cast<ContentItem>(); return Enumerable.Empty<Page>();
break;
} }
return contentItems.Select(ci => ci.As<Page>());
} }
public Page Get(int id) { public Page Get(int id) {
@@ -79,6 +73,7 @@ namespace Orchard.Pages.Services {
public void Publish(Page page) { public void Publish(Page page) {
_publishingTaskManager.DeleteTasks(page.ContentItem); _publishingTaskManager.DeleteTasks(page.ContentItem);
_contentManager.Publish(page.ContentItem); _contentManager.Publish(page.ContentItem);
_slugConstraint.AddPublishedSlug(page.Slug);
} }
public void Publish(Page page, DateTime scheduledPublishUtc) { public void Publish(Page page, DateTime scheduledPublishUtc) {
@@ -87,6 +82,7 @@ namespace Orchard.Pages.Services {
public void Unpublish(Page page) { public void Unpublish(Page page) {
_contentManager.Unpublish(page.ContentItem); _contentManager.Unpublish(page.ContentItem);
_slugConstraint.RemovePublishedSlug(page.Slug);
} }
public DateTime? GetScheduledPublishUtc(Page page) { public DateTime? GetScheduledPublishUtc(Page page) {

View File

@@ -3,35 +3,73 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Web;
using System.Web.Routing; using System.Web.Routing;
using Orchard.Logging;
namespace Orchard.Pages.Services { namespace Orchard.Pages.Services {
public interface ISlugConstraint : IRouteConstraint, ISingletonDependency { public interface ISlugConstraint : IRouteConstraint, ISingletonDependency {
void SetCurrentlyPublishedSlugs(IEnumerable<string> slugs); void SetCurrentlyPublishedSlugs(IEnumerable<string> slugs);
string LookupPublishedSlug(string slug); string LookupPublishedSlug(string slug);
void AddPublishedSlug(string slug);
void RemovePublishedSlug(string slug);
} }
public class SlugConstraint : ISlugConstraint { 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>(); 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) { 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) .Distinct(StringComparer.OrdinalIgnoreCase)
.ToDictionary(value => value, StringComparer.OrdinalIgnoreCase); .ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
} }
Logger.Debug("Publishing slugs: {0}", string.Join(", ", valuesArray));
}
public string LookupPublishedSlug(string slug) { public string LookupPublishedSlug(string slug) {
lock (_syncLock) {
string actual; string actual;
if (_currentlyPublishedSlugs.TryGetValue(slug, out actual)) if (_currentlyPublishedSlugs.TryGetValue(slug, out actual))
return actual; return actual;
return slug; 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) { public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
object value; object value;
if (values.TryGetValue(parameterName, out value)) { if (values.TryGetValue(parameterName, out value)) {
var parameterValue = Convert.ToString(value); var parameterValue = Convert.ToString(value);
lock (_syncLock) {
return _currentlyPublishedSlugs.ContainsKey(parameterValue); return _currentlyPublishedSlugs.ContainsKey(parameterValue);
} }
}
return false; 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 { namespace Orchard.Roles {
[UsedImplicitly] [UsedImplicitly]
public class Extension : IExtensionManagerEvents { public class Extension : ExtensionManagerEvents {
private readonly IRoleService _roleService; private readonly IRoleService _roleService;
private readonly IEnumerable<IPermissionProvider> _permissionProviders; private readonly IEnumerable<IPermissionProvider> _permissionProviders;
@@ -18,10 +18,7 @@ namespace Orchard.Roles {
_permissionProviders = permissionProviders; _permissionProviders = permissionProviders;
} }
public void Enabling(ExtensionEventContext context) { public override void Enabled(ExtensionEventContext context) {
}
public void Enabled(ExtensionEventContext context) {
// when another package is being enabled, locate matching permission providers // when another package is being enabled, locate matching permission providers
var providersForEnabledPackage = var providersForEnabledPackage =
_permissionProviders.Where(x => x.PackageName == context.Extension.Descriptor.Name); _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() { protected virtual void Initialize() {
var shell = CreateShell(); var shellContainer = CreateShellContainer();
var shell = shellContainer.Resolve<IOrchardShell>();
shell.Activate(); shell.Activate();
_current = shell; _current = shell;
@@ -46,7 +47,14 @@ namespace Orchard.Environment {
_controllerBuilder.SetControllerFactory(new OrchardControllerFactory()); _controllerBuilder.SetControllerFactory(new OrchardControllerFactory());
ServiceLocator.SetLocator(t => _containerProvider.RequestContainer.Resolve(t)); 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 tempContainer = CreateShellContainer();
var containerProvider = new FiniteContainerProvider(tempContainer); var containerProvider = new FiniteContainerProvider(tempContainer);
try { try {
@@ -60,7 +68,19 @@ namespace Orchard.Environment {
containerProvider.DisposeRequestContainer(); containerProvider.DisposeRequestContainer();
tempContainer.Dispose(); 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() { 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.Logging;
using Orchard.Utility; using Orchard.Utility;
namespace Orchard.Extensions { namespace Orchard.Extensions {
public interface IHackInstallationGenerator : IDependency { public interface IHackInstallationGenerator : IDependency {
void GenerateInstallEvents(); void GenerateInstallEvents();
void GenerateActivateEvents();
} }
public class HackInstallationGenerator : IHackInstallationGenerator { public class HackInstallationGenerator : IHackInstallationGenerator {
@@ -22,7 +24,6 @@ namespace Orchard.Extensions {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public void GenerateInstallEvents() { public void GenerateInstallEvents() {
//TEMP: this is really part of the extension manager's job. an extension //TEMP: this is really part of the extension manager's job. an extension
// install event is being simulated here on each web app startup // install event is being simulated here on each web app startup
var enabled = new List<ExtensionEntry>(); var enabled = new List<ExtensionEntry>();
@@ -37,5 +38,18 @@ namespace Orchard.Extensions {
_extensionEvents.Invoke(x => x.Enabled(context), Logger); _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 Enabled(ExtensionEventContext context);
void Disabling(ExtensionEventContext context); void Disabling(ExtensionEventContext context);
void Disabled(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 { public class ExtensionEventContext {

View File

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

View File

@@ -14,7 +14,7 @@ namespace Orchard.Tasks {
_timer = new Timer(); _timer = new Timer();
_timer.Elapsed += Elapsed; _timer.Elapsed += Elapsed;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
Interval = TimeSpan.FromSeconds(30); Interval = TimeSpan.FromMinutes(5);
} }
public ILogger Logger { get; set; } public ILogger Logger { get; set; }