mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +08:00
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
This commit is contained in:
@@ -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" />
|
||||||
|
@@ -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) {
|
||||||
|
@@ -3,34 +3,72 @@ 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
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
string[] valuesArray = values.ToArray();
|
||||||
.ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
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) {
|
public string LookupPublishedSlug(string slug) {
|
||||||
string actual;
|
lock (_syncLock) {
|
||||||
if (_currentlyPublishedSlugs.TryGetValue(slug, out actual))
|
string actual;
|
||||||
return actual;
|
if (_currentlyPublishedSlugs.TryGetValue(slug, out actual))
|
||||||
return slug;
|
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) {
|
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);
|
||||||
return _currentlyPublishedSlugs.ContainsKey(parameterValue);
|
|
||||||
|
lock (_syncLock) {
|
||||||
|
return _currentlyPublishedSlugs.ContainsKey(parameterValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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,12 +47,19 @@ 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 {
|
||||||
var requestContainer = containerProvider.RequestContainer;
|
var requestContainer = containerProvider.RequestContainer;
|
||||||
|
|
||||||
var hackInstallationGenerator = requestContainer.Resolve<IHackInstallationGenerator>();
|
var hackInstallationGenerator = requestContainer.Resolve<IHackInstallationGenerator>();
|
||||||
hackInstallationGenerator.GenerateInstallEvents();
|
hackInstallationGenerator.GenerateInstallEvents();
|
||||||
}
|
}
|
||||||
@@ -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() {
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
|
@@ -23,5 +23,4 @@ namespace Orchard.Tasks {
|
|||||||
_tasks.Invoke(task => task.Sweep(), Logger);
|
_tasks.Invoke(task => task.Sweep(), Logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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; }
|
||||||
|
Reference in New Issue
Block a user