diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs index 7910e875f..d0e5f6137 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs @@ -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(BlogDriver.ContentType.Name); - + var blog = Services.ContentManager.New(BlogDriver.ContentType.Name); if (blog == null) return new NotFoundResult(); @@ -59,13 +58,10 @@ namespace Orchard.Blogs.Controllers { if (!ModelState.IsValid) return View(model); - - Services.ContentManager.Create(model.Blog.Item.ContentItem); - //TEMP: (erikpo) ensure information has committed for this record - Services.ContentManager.Flush(); + _blogService.Create(model.Blog.Item); - return Redirect(Url.BlogForAdmin(model.Blog.Item.As().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()); diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs index 529217c4b..ed0a60822 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs @@ -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(); diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj index d7222a565..4403add2f 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj @@ -31,14 +31,6 @@ 4 - - False - ..\..\..\..\lib\autofac\Autofac.dll - - - False - ..\..\..\..\lib\autofac\Autofac.Integration.Web.dll - @@ -83,8 +75,10 @@ + - + + @@ -180,10 +174,6 @@ {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core - - {79AED36E-ABD0-4747-93D3-8722B042454B} - Orchard.Users - diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs index 2b0e4153e..ba3298310 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs @@ -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 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"} diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraint.cs new file mode 100644 index 000000000..ad79960f0 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraint.cs @@ -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 { + /// + /// Singleton object, per Orchard Shell instance. We need to protect concurrent access to the dictionary. + /// + private readonly object _syncLock = new object(); + private IDictionary _slugs = new Dictionary(); + + public BlogSlugConstraint() { + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public void SetSlugs(IEnumerable 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; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraintUpdator.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraintUpdator.cs new file mode 100644 index 000000000..5dbe0d34f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/BlogSlugConstraintUpdator.cs @@ -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)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IBlogSlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IBlogSlugConstraint.cs new file mode 100644 index 000000000..5c47fad3a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IBlogSlugConstraint.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Web.Routing; + +namespace Orchard.Blogs.Routing { + public interface IBlogSlugConstraint : IRouteConstraint, ISingletonDependency { + void SetSlugs(IEnumerable slugs); + string FindSlug(string slug); + void AddSlug(string slug); + void RemoveSlug(string slug); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IsBlogConstraint.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IsBlogConstraint.cs deleted file mode 100644 index 972a82531..000000000 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Routing/IsBlogConstraint.cs +++ /dev/null @@ -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().Get(values[parameterName].ToString()) != null; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogHomePageProvider.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogHomePageProvider.cs index 466151941..d35b352f4 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogHomePageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogHomePageProvider.cs @@ -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") }; diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs index c2fb55e6c..5a67d021c 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs @@ -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); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogService.cs index 3daeb7d7d..b5f8c25b1 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/IBlogService.cs @@ -5,6 +5,8 @@ namespace Orchard.Blogs.Services { public interface IBlogService : IDependency { Blog Get(string slug); IEnumerable Get(); + void Create(Blog blog); + void Edit(Blog blog); void Delete(Blog blog); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Pages/Controllers/AdminController.cs index 6ee4ad354..affd72536 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Controllers/AdminController.cs @@ -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(PageDriver.ContentType.Name)); + var page = Services.ContentManager.New(PageDriver.ContentType.Name); var model = new PageCreateViewModel { - Page = page + Page = Services.ContentManager.BuildEditorModel(page) }; return View(model); diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Controllers/PageController.cs b/src/Orchard.Web/Modules/Orchard.Pages/Controllers/PageController.cs index dcac1ed92..9511ebc4d 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Controllers/PageController.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Controllers/PageController.cs @@ -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(); diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Orchard.Pages.csproj b/src/Orchard.Web/Modules/Orchard.Pages/Orchard.Pages.csproj index 6aac99156..05dd70c26 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Orchard.Pages.csproj +++ b/src/Orchard.Web/Modules/Orchard.Pages/Orchard.Pages.csproj @@ -76,13 +76,13 @@ - + - + Code - + diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routes.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routes.cs index 07db9123c..544dce5d4 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Routes.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Routes.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 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 { } }; } - } } diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routing/IPageSlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routing/IPageSlugConstraint.cs new file mode 100644 index 000000000..7c3adc37f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Pages/Routing/IPageSlugConstraint.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Web.Routing; + +namespace Orchard.Pages.Routing { + public interface IPageSlugConstraint : IRouteConstraint, ISingletonDependency { + void SetSlugs(IEnumerable slugs); + string FindSlug(string slug); + void AddSlug(string slug); + void RemoveSlug(string slug); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routing/ISlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routing/ISlugConstraint.cs deleted file mode 100644 index 84a661715..000000000 --- a/src/Orchard.Web/Modules/Orchard.Pages/Routing/ISlugConstraint.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using System.Web.Routing; - -namespace Orchard.Pages.Routing { - public interface ISlugConstraint : IRouteConstraint, ISingletonDependency { - void SetCurrentlyPublishedSlugs(IEnumerable slugs); - string LookupPublishedSlug(string slug); - void AddPublishedSlug(string slug); - void RemovePublishedSlug(string slug); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraint.cs new file mode 100644 index 000000000..730051451 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraint.cs @@ -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 { + /// + /// Singleton object, per Orchard Shell instance. We need to protect concurrent access to the dictionary. + /// + private readonly object _syncLock = new object(); + private IDictionary _slugs = new Dictionary(); + + public PageSlugConstraint() { + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public void SetSlugs(IEnumerable 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; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraintUpdator.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraintUpdator.cs similarity index 56% rename from src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraintUpdator.cs rename to src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraintUpdator.cs index fcba8b2a9..8910e4620 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraintUpdator.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Routing/PageSlugConstraintUpdator.cs @@ -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)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraint.cs b/src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraint.cs deleted file mode 100644 index aa909c54e..000000000 --- a/src/Orchard.Web/Modules/Orchard.Pages/Routing/SlugConstraint.cs +++ /dev/null @@ -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 { - /// - /// 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) { - // 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; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Services/PageHomePageProvider.cs b/src/Orchard.Web/Modules/Orchard.Pages/Services/PageHomePageProvider.cs index b03d3b5f1..b73573924 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Services/PageHomePageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Services/PageHomePageProvider.cs @@ -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(); diff --git a/src/Orchard.Web/Modules/Orchard.Pages/Services/PageService.cs b/src/Orchard.Web/Modules/Orchard.Pages/Services/PageService.cs index 3d9f6b83d..22160fcbf 100644 --- a/src/Orchard.Web/Modules/Orchard.Pages/Services/PageService.cs +++ b/src/Orchard.Web/Modules/Orchard.Pages/Services/PageService.cs @@ -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) {