mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Changed blog constraint to be a singleton like page constraint and made them consistent
--HG-- branch : dev rename : src/Orchard.Web/Modules/Orchard.Blogs/Routing/IsBlogConstraint.cs => src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraint.cs rename : src/Orchard.Web/Modules/Orchard.Pages/Routing/ISlugConstraint.cs => src/Orchard.Web/Modules/Orchard.Pages/Routing/IPageSlugConstraint.cs rename : src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraint.cs => src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraint.cs rename : src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraintUpdator.cs => src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraintUpdator.cs
This commit is contained in:
@@ -37,8 +37,7 @@ namespace Orchard.Blogs.Controllers {
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageBlogs, T("Not allowed to create blogs")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
Blog blog = Services.ContentManager.New<Blog>(BlogDriver.ContentType.Name);
|
||||
|
||||
var blog = Services.ContentManager.New<Blog>(BlogDriver.ContentType.Name);
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
@@ -60,12 +59,9 @@ namespace Orchard.Blogs.Controllers {
|
||||
if (!ModelState.IsValid)
|
||||
return View(model);
|
||||
|
||||
Services.ContentManager.Create(model.Blog.Item.ContentItem);
|
||||
_blogService.Create(model.Blog.Item);
|
||||
|
||||
//TEMP: (erikpo) ensure information has committed for this record
|
||||
Services.ContentManager.Flush();
|
||||
|
||||
return Redirect(Url.BlogForAdmin(model.Blog.Item.As<RoutableAspect>().Slug));
|
||||
return Redirect(Url.BlogForAdmin(model.Blog.Item.Slug));
|
||||
}
|
||||
|
||||
public ActionResult Edit(string blogSlug) {
|
||||
@@ -74,8 +70,7 @@ namespace Orchard.Blogs.Controllers {
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
//TODO: (erikpo) Move looking up the current blog up into a modelbinder
|
||||
Blog blog = _blogService.Get(blogSlug);
|
||||
|
||||
var blog = _blogService.Get(blogSlug);
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
@@ -92,8 +87,7 @@ namespace Orchard.Blogs.Controllers {
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
//TODO: (erikpo) Move looking up the current blog up into a modelbinder
|
||||
Blog blog = _blogService.Get(blogSlug);
|
||||
|
||||
var blog = _blogService.Get(blogSlug);
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
@@ -109,6 +103,8 @@ namespace Orchard.Blogs.Controllers {
|
||||
CurrentSite.HomePage = "BlogHomePageProvider;" + model.Blog.Item.Id;
|
||||
}
|
||||
|
||||
_blogService.Edit(model.Blog.Item);
|
||||
|
||||
Services.Notifier.Information(T("Blog information updated"));
|
||||
|
||||
return Redirect(Url.BlogsForAdmin());
|
||||
|
@@ -5,6 +5,7 @@ using System.Web.Routing;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Blogs.Extensions;
|
||||
using Orchard.Blogs.Models;
|
||||
using Orchard.Blogs.Routing;
|
||||
using Orchard.Blogs.Services;
|
||||
using Orchard.Blogs.ViewModels;
|
||||
using Orchard.Core.Feeds;
|
||||
@@ -15,16 +16,14 @@ namespace Orchard.Blogs.Controllers {
|
||||
public class BlogController : Controller {
|
||||
private readonly IOrchardServices _services;
|
||||
private readonly IBlogService _blogService;
|
||||
private readonly IBlogSlugConstraint _blogSlugConstraint;
|
||||
private readonly IFeedManager _feedManager;
|
||||
private readonly RouteCollection _routeCollection;
|
||||
|
||||
public BlogController(
|
||||
IOrchardServices services,
|
||||
IBlogService blogService,
|
||||
IFeedManager feedManager,
|
||||
RouteCollection routeCollection) {
|
||||
public BlogController(IOrchardServices services, IBlogService blogService, IBlogSlugConstraint blogSlugConstraint, IFeedManager feedManager, RouteCollection routeCollection) {
|
||||
_services = services;
|
||||
_blogService = blogService;
|
||||
_blogSlugConstraint = blogSlugConstraint;
|
||||
_feedManager = feedManager;
|
||||
_routeCollection = routeCollection;
|
||||
Logger = NullLogger.Instance;
|
||||
@@ -42,8 +41,11 @@ namespace Orchard.Blogs.Controllers {
|
||||
|
||||
//TODO: (erikpo) Should move the slug parameter and get call and null check up into a model binder
|
||||
public ActionResult Item(string blogSlug) {
|
||||
Blog blog = _blogService.Get(blogSlug);
|
||||
var correctedSlug = _blogSlugConstraint.FindSlug(blogSlug);
|
||||
if (correctedSlug == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
var blog = _blogService.Get(correctedSlug);
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
|
@@ -31,14 +31,6 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=1.4.4.561, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\autofac\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Autofac.Integration.Web, Version=1.4.4.561, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\autofac\Autofac.Integration.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||
@@ -83,8 +75,10 @@
|
||||
<Compile Include="Handlers\BlogArchiveHandler.cs" />
|
||||
<Compile Include="Models\BlogArchiveRecord.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
<Compile Include="Routing\IBlogSlugConstraint.cs" />
|
||||
<Compile Include="Routing\IsArchiveConstraint.cs" />
|
||||
<Compile Include="Routing\IsBlogConstraint.cs" />
|
||||
<Compile Include="Routing\BlogSlugConstraint.cs" />
|
||||
<Compile Include="Routing\BlogSlugConstraintUpdator.cs" />
|
||||
<Compile Include="Services\BlogHomePageProvider.cs" />
|
||||
<Compile Include="Services\BlogService.cs" />
|
||||
<Compile Include="Controllers\BlogController.cs" />
|
||||
@@ -180,10 +174,6 @@
|
||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||
<Name>Orchard.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Users\Orchard.Users.csproj">
|
||||
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
|
||||
<Name>Orchard.Users</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
|
@@ -1,17 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Blogs.Routing;
|
||||
using Orchard.Mvc.Routes;
|
||||
|
||||
namespace Orchard.Blogs {
|
||||
public class Routes : IRouteProvider
|
||||
{
|
||||
private readonly IContainerProvider _containerProvider;
|
||||
public class Routes : IRouteProvider {
|
||||
private readonly IBlogSlugConstraint _blogSlugConstraint;
|
||||
|
||||
public Routes(IContainerProvider containerProvider) {
|
||||
_containerProvider = containerProvider;
|
||||
public Routes(IBlogSlugConstraint blogSlugConstraint) {
|
||||
_blogSlugConstraint = blogSlugConstraint;
|
||||
}
|
||||
|
||||
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||
@@ -44,7 +42,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Edit"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -60,7 +58,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Delete"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -76,7 +74,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Item"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -92,7 +90,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Create"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -108,7 +106,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Edit"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -124,7 +122,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Delete"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -140,7 +138,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Publish"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -156,7 +154,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Unpublish"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -200,7 +198,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "ListByArchive"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)},
|
||||
{"blogSlug", _blogSlugConstraint},
|
||||
{"archiveData", new IsArchiveConstraint()}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
@@ -217,7 +215,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "LiveWriterManifest"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -233,7 +231,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Rsd"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -249,7 +247,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Item"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
@@ -265,7 +263,7 @@ namespace Orchard.Blogs {
|
||||
{"action", "Item"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"blogSlug", new IsBlogConstraint(_containerProvider)}
|
||||
{"blogSlug", _blogSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Blogs"}
|
||||
|
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Blogs.Routing {
|
||||
[UsedImplicitly]
|
||||
public class BlogSlugConstraint : IBlogSlugConstraint {
|
||||
/// <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> _slugs = new Dictionary<string, string>();
|
||||
|
||||
public BlogSlugConstraint() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void SetSlugs(IEnumerable<string> slugs) {
|
||||
// Make a copy to avoid performing potential lazy computation inside the lock
|
||||
var slugsArray = slugs.ToArray();
|
||||
|
||||
lock (_syncLock) {
|
||||
_slugs = slugsArray.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
Logger.Debug("Blog slugs: {0}", string.Join(", ", slugsArray));
|
||||
}
|
||||
|
||||
public string FindSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
string actual;
|
||||
return _slugs.TryGetValue(slug, out actual) ? actual : slug;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
_slugs[slug] = slug;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
_slugs.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 _slugs.ContainsKey(parameterValue);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Blogs.Services;
|
||||
using Orchard.Extensions;
|
||||
using Orchard.Tasks;
|
||||
|
||||
namespace Orchard.Blogs.Routing {
|
||||
[UsedImplicitly]
|
||||
public class BlogSlugConstraintUpdator : ExtensionManagerEvents, IBackgroundTask {
|
||||
private readonly IBlogSlugConstraint _blogSlugConstraint;
|
||||
private readonly IBlogService _blogService;
|
||||
|
||||
public BlogSlugConstraintUpdator(IBlogSlugConstraint blogSlugConstraint, IBlogService blogService) {
|
||||
_blogSlugConstraint = blogSlugConstraint;
|
||||
_blogService = blogService;
|
||||
}
|
||||
|
||||
public override void Activated(ExtensionEventContext context) {
|
||||
if (context.Extension.Descriptor.Name == "Orchard.Blogs") {
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Sweep() {
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void Refresh() {
|
||||
_blogSlugConstraint.SetSlugs(_blogService.Get().Select(b => b.Slug));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Orchard.Blogs.Routing {
|
||||
public interface IBlogSlugConstraint : IRouteConstraint, ISingletonDependency {
|
||||
void SetSlugs(IEnumerable<string> slugs);
|
||||
string FindSlug(string slug);
|
||||
void AddSlug(string slug);
|
||||
void RemoveSlug(string slug);
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Blogs.Services;
|
||||
|
||||
namespace Orchard.Blogs.Routing {
|
||||
public class IsBlogConstraint : IRouteConstraint {
|
||||
private readonly IContainerProvider _containerProvider;
|
||||
|
||||
public IsBlogConstraint(IContainerProvider containerProvider) {
|
||||
_containerProvider = containerProvider;
|
||||
}
|
||||
|
||||
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
|
||||
return _containerProvider.RequestContainer.Resolve<IBlogService>().Get(values[parameterName].ToString()) != null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
using System.Web.Mvc;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Blogs.Extensions;
|
||||
using Orchard.Blogs.Routing;
|
||||
using Orchard.Blogs.ViewModels;
|
||||
using Orchard.Mvc.Results;
|
||||
using Orchard.Services;
|
||||
@@ -11,12 +12,14 @@ namespace Orchard.Blogs.Services {
|
||||
[UsedImplicitly]
|
||||
public class BlogHomePageProvider : IHomePageProvider {
|
||||
private readonly IBlogService _blogService;
|
||||
private readonly IBlogSlugConstraint _blogSlugConstraint;
|
||||
private readonly IFeedManager _feedManager;
|
||||
|
||||
public BlogHomePageProvider(IOrchardServices services, IBlogService blogService, IFeedManager feedManager) {
|
||||
public BlogHomePageProvider(IOrchardServices services, IBlogService blogService, IBlogSlugConstraint blogSlugConstraint, IFeedManager feedManager) {
|
||||
Services = services;
|
||||
_feedManager = feedManager;
|
||||
_blogService = blogService;
|
||||
_blogSlugConstraint = blogSlugConstraint;
|
||||
_feedManager = feedManager;
|
||||
}
|
||||
|
||||
public IOrchardServices Services { get; private set; }
|
||||
@@ -30,6 +33,14 @@ namespace Orchard.Blogs.Services {
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
var correctedSlug = _blogSlugConstraint.FindSlug(blog.Slug);
|
||||
if (correctedSlug == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
blog = _blogService.Get(correctedSlug);
|
||||
if (blog == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
var model = new BlogViewModel {
|
||||
Blog = Services.ContentManager.BuildDisplayModel(blog, "Detail")
|
||||
};
|
||||
|
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Blogs.Models;
|
||||
using Orchard.Blogs.Routing;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
@@ -9,9 +10,11 @@ namespace Orchard.Blogs.Services {
|
||||
[UsedImplicitly]
|
||||
public class BlogService : IBlogService {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IBlogSlugConstraint _blogSlugConstraint;
|
||||
|
||||
public BlogService(IContentManager contentManager) {
|
||||
public BlogService(IContentManager contentManager, IBlogSlugConstraint blogSlugConstraint) {
|
||||
_contentManager = contentManager;
|
||||
_blogSlugConstraint = blogSlugConstraint;
|
||||
}
|
||||
|
||||
public Blog Get(string slug) {
|
||||
@@ -27,8 +30,18 @@ namespace Orchard.Blogs.Services {
|
||||
.List();
|
||||
}
|
||||
|
||||
public void Create(Blog blog) {
|
||||
_contentManager.Create(blog.ContentItem);
|
||||
_blogSlugConstraint.AddSlug(blog.Slug);
|
||||
}
|
||||
|
||||
public void Edit(Blog blog) {
|
||||
_blogSlugConstraint.AddSlug(blog.Slug);
|
||||
}
|
||||
|
||||
public void Delete(Blog blog) {
|
||||
_contentManager.Remove(blog.ContentItem);
|
||||
_blogSlugConstraint.RemoveSlug(blog.Slug);
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,6 +5,8 @@ namespace Orchard.Blogs.Services {
|
||||
public interface IBlogService : IDependency {
|
||||
Blog Get(string slug);
|
||||
IEnumerable<Blog> Get();
|
||||
void Create(Blog blog);
|
||||
void Edit(Blog blog);
|
||||
void Delete(Blog blog);
|
||||
}
|
||||
}
|
@@ -110,10 +110,10 @@ namespace Orchard.Pages.Controllers {
|
||||
if (!Services.Authorizer.Authorize(Permissions.EditPages, T("Not allowed to create a page")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var page = Services.ContentManager.BuildEditorModel(Services.ContentManager.New<Page>(PageDriver.ContentType.Name));
|
||||
var page = Services.ContentManager.New<Page>(PageDriver.ContentType.Name);
|
||||
|
||||
var model = new PageCreateViewModel {
|
||||
Page = page
|
||||
Page = Services.ContentManager.BuildEditorModel(page)
|
||||
};
|
||||
|
||||
return View(model);
|
||||
|
@@ -10,12 +10,12 @@ namespace Orchard.Pages.Controllers {
|
||||
[ValidateInput(false)]
|
||||
public class PageController : Controller {
|
||||
private readonly IPageService _pageService;
|
||||
private readonly ISlugConstraint _slugConstraint;
|
||||
private readonly IPageSlugConstraint _pageSlugConstraint;
|
||||
|
||||
public PageController(IOrchardServices services, IPageService pageService, ISlugConstraint slugConstraint) {
|
||||
public PageController(IOrchardServices services, IPageService pageService, IPageSlugConstraint pageSlugConstraint) {
|
||||
Services = services;
|
||||
_pageService = pageService;
|
||||
_slugConstraint = slugConstraint;
|
||||
_pageSlugConstraint = pageSlugConstraint;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Orchard.Pages.Controllers {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.AccessFrontEnd, T("Couldn't view page")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var correctedSlug = _slugConstraint.LookupPublishedSlug(slug);
|
||||
var correctedSlug = _pageSlugConstraint.FindSlug(slug);
|
||||
if (correctedSlug == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
|
@@ -76,13 +76,13 @@
|
||||
<Compile Include="Routes.cs" />
|
||||
<Compile Include="Security\Authorization.cs" />
|
||||
<Compile Include="Services\IPageService.cs" />
|
||||
<Compile Include="Routing\ISlugConstraint.cs" />
|
||||
<Compile Include="Routing\IPageSlugConstraint.cs" />
|
||||
<Compile Include="Services\PageService.cs" />
|
||||
<Compile Include="Services\PageHomePageProvider.cs" />
|
||||
<Compile Include="Routing\SlugConstraint.cs">
|
||||
<Compile Include="Routing\PageSlugConstraint.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Routing\SlugConstraintUpdator.cs" />
|
||||
<Compile Include="Routing\PageSlugConstraintUpdator.cs" />
|
||||
<Compile Include="ViewModels\PageCreateViewModel.cs" />
|
||||
<Compile Include="ViewModels\PageEditViewModel.cs" />
|
||||
<Compile Include="ViewModels\PagesViewModel.cs" />
|
||||
|
@@ -6,10 +6,10 @@ using Orchard.Pages.Routing;
|
||||
|
||||
namespace Orchard.Pages {
|
||||
public class Routes : IRouteProvider {
|
||||
private readonly ISlugConstraint _slugConstraint;
|
||||
private readonly IPageSlugConstraint _pageSlugConstraint;
|
||||
|
||||
public Routes(ISlugConstraint slugConstraint) {
|
||||
_slugConstraint = slugConstraint;
|
||||
public Routes(IPageSlugConstraint pageSlugConstraint) {
|
||||
_pageSlugConstraint = pageSlugConstraint;
|
||||
}
|
||||
|
||||
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||
@@ -29,7 +29,7 @@ namespace Orchard.Pages {
|
||||
{"action", "item"}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"slug", _slugConstraint}
|
||||
{"slug", _pageSlugConstraint}
|
||||
},
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Pages"}
|
||||
@@ -38,6 +38,5 @@ namespace Orchard.Pages {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Orchard.Pages.Routing {
|
||||
public interface IPageSlugConstraint : IRouteConstraint, ISingletonDependency {
|
||||
void SetSlugs(IEnumerable<string> slugs);
|
||||
string FindSlug(string slug);
|
||||
void AddSlug(string slug);
|
||||
void RemoveSlug(string slug);
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Routing;
|
||||
|
||||
namespace Orchard.Pages.Routing {
|
||||
public interface ISlugConstraint : IRouteConstraint, ISingletonDependency {
|
||||
void SetCurrentlyPublishedSlugs(IEnumerable<string> slugs);
|
||||
string LookupPublishedSlug(string slug);
|
||||
void AddPublishedSlug(string slug);
|
||||
void RemovePublishedSlug(string slug);
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Pages.Routing {
|
||||
[UsedImplicitly]
|
||||
public class PageSlugConstraint : IPageSlugConstraint {
|
||||
/// <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> _slugs = new Dictionary<string, string>();
|
||||
|
||||
public PageSlugConstraint() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void SetSlugs(IEnumerable<string> slugs) {
|
||||
// Make a copy to avoid performing potential lazy computation inside the lock
|
||||
var slugsArray = slugs.ToArray();
|
||||
|
||||
lock (_syncLock) {
|
||||
_slugs = slugsArray.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
Logger.Debug("Page slugs: {0}", string.Join(", ", slugsArray));
|
||||
}
|
||||
|
||||
public string FindSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
string actual;
|
||||
return _slugs.TryGetValue(slug, out actual) ? actual : slug;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
_slugs[slug] = slug;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSlug(string slug) {
|
||||
lock (_syncLock) {
|
||||
_slugs.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 _slugs.ContainsKey(parameterValue);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,12 +6,12 @@ using Orchard.Tasks;
|
||||
|
||||
namespace Orchard.Pages.Routing {
|
||||
[UsedImplicitly]
|
||||
public class SlugConstraintUpdator : ExtensionManagerEvents, IBackgroundTask {
|
||||
private readonly ISlugConstraint _slugConstraint;
|
||||
public class PageSlugConstraintUpdator : ExtensionManagerEvents, IBackgroundTask {
|
||||
private readonly IPageSlugConstraint _pageSlugConstraint;
|
||||
private readonly IPageService _pageService;
|
||||
|
||||
public SlugConstraintUpdator(ISlugConstraint slugConstraint, IPageService pageService) {
|
||||
_slugConstraint = slugConstraint;
|
||||
public PageSlugConstraintUpdator(IPageSlugConstraint pageSlugConstraint, IPageService pageService) {
|
||||
_pageSlugConstraint = pageSlugConstraint;
|
||||
_pageService = pageService;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Orchard.Pages.Routing {
|
||||
}
|
||||
|
||||
private void Refresh() {
|
||||
_slugConstraint.SetCurrentlyPublishedSlugs(_pageService.Get(PageStatus.Published).Select(page => page.Slug));
|
||||
_pageSlugConstraint.SetSlugs(_pageService.Get(PageStatus.Published).Select(p => p.Slug));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Pages.Routing {
|
||||
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) {
|
||||
// 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[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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,11 +10,11 @@ namespace Orchard.Pages.Services {
|
||||
[UsedImplicitly]
|
||||
public class PageHomePageProvider : IHomePageProvider {
|
||||
private readonly IPageService _pageService;
|
||||
private readonly ISlugConstraint _slugConstraint;
|
||||
private readonly IPageSlugConstraint _pageSlugConstraint;
|
||||
|
||||
public PageHomePageProvider(IOrchardServices services, IPageService pageService, ISlugConstraint slugConstraint) {
|
||||
public PageHomePageProvider(IOrchardServices services, IPageService pageService, IPageSlugConstraint pageSlugConstraint) {
|
||||
Services = services;
|
||||
_slugConstraint = slugConstraint;
|
||||
_pageSlugConstraint = pageSlugConstraint;
|
||||
_pageService = pageService;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace Orchard.Pages.Services {
|
||||
if (page == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
var correctedSlug = _slugConstraint.LookupPublishedSlug(page.Slug);
|
||||
var correctedSlug = _pageSlugConstraint.FindSlug(page.Slug);
|
||||
if (correctedSlug == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
|
@@ -15,12 +15,12 @@ namespace Orchard.Pages.Services {
|
||||
public class PageService : IPageService {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IPublishingTaskManager _publishingTaskManager;
|
||||
private readonly ISlugConstraint _slugConstraint;
|
||||
private readonly IPageSlugConstraint _pageSlugConstraint;
|
||||
|
||||
public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager, ISlugConstraint slugConstraint) {
|
||||
public PageService(IContentManager contentManager, IPublishingTaskManager publishingTaskManager, IPageSlugConstraint pageSlugConstraint) {
|
||||
_contentManager = contentManager;
|
||||
_publishingTaskManager = publishingTaskManager;
|
||||
_slugConstraint = slugConstraint;
|
||||
_pageSlugConstraint = pageSlugConstraint;
|
||||
}
|
||||
|
||||
public int GetCount() {
|
||||
@@ -82,7 +82,7 @@ namespace Orchard.Pages.Services {
|
||||
public void Publish(Page page) {
|
||||
_publishingTaskManager.DeleteTasks(page.ContentItem);
|
||||
_contentManager.Publish(page.ContentItem);
|
||||
_slugConstraint.AddPublishedSlug(page.Slug);
|
||||
_pageSlugConstraint.AddSlug(page.Slug);
|
||||
}
|
||||
|
||||
public void Publish(Page page, DateTime scheduledPublishUtc) {
|
||||
@@ -91,7 +91,7 @@ namespace Orchard.Pages.Services {
|
||||
|
||||
public void Unpublish(Page page) {
|
||||
_contentManager.Unpublish(page.ContentItem);
|
||||
_slugConstraint.RemovePublishedSlug(page.Slug);
|
||||
_pageSlugConstraint.RemoveSlug(page.Slug);
|
||||
}
|
||||
|
||||
public DateTime? GetScheduledPublishUtc(Page page) {
|
||||
|
Reference in New Issue
Block a user