#17261 Changing BlogSlugConstraint to BlogPathContraint to handle homepage blogs

Work Item: 17261

--HG--
branch : dev
extra : transplant_source : Y%BC%1F%0E%A2%C5%10%BE%3B%82P%21%FC%FA%ED%FE%A7%26%9B%92
This commit is contained in:
Sebastien Ros
2011-01-31 13:25:16 -08:00
parent fc261cdb3a
commit 2680f394ba
15 changed files with 122 additions and 88 deletions

View File

@@ -24,7 +24,7 @@ namespace Orchard.Blogs.Controllers {
private readonly IBlogPostService _blogPostService;
private readonly IContentManager _contentManager;
private readonly ITransactionManager _transactionManager;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IBlogPathConstraint _blogPathConstraint;
private readonly ISiteService _siteService;
public BlogAdminController(
@@ -33,7 +33,7 @@ namespace Orchard.Blogs.Controllers {
IBlogPostService blogPostService,
IContentManager contentManager,
ITransactionManager transactionManager,
IBlogSlugConstraint blogSlugConstraint,
IBlogPathConstraint blogPathConstraint,
ISiteService siteService,
IShapeFactory shapeFactory) {
Services = services;
@@ -41,7 +41,7 @@ namespace Orchard.Blogs.Controllers {
_blogPostService = blogPostService;
_contentManager = contentManager;
_transactionManager = transactionManager;
_blogSlugConstraint = blogSlugConstraint;
_blogPathConstraint = blogPathConstraint;
_siteService = siteService;
T = NullLocalizer.Instance;
Shape = shapeFactory;
@@ -81,7 +81,7 @@ namespace Orchard.Blogs.Controllers {
}
_contentManager.Publish(blog.ContentItem);
_blogSlugConstraint.AddSlug(blog.As<IRoutableAspect>().GetEffectiveSlug());
_blogPathConstraint.AddPath(blog.As<IRoutableAspect>().Path);
return Redirect(Url.BlogForAdmin(blog));
}
@@ -116,7 +116,7 @@ namespace Orchard.Blogs.Controllers {
}
_contentManager.Publish(blog);
_blogSlugConstraint.AddSlug(blog.As<IRoutableAspect>().GetEffectiveSlug());
_blogPathConstraint.AddPath(blog.As<IRoutableAspect>().Path);
Services.Notifier.Information(T("Blog information updated"));
return Redirect(Url.BlogsForAdmin());

View File

@@ -20,7 +20,7 @@ namespace Orchard.Blogs.Controllers {
private readonly IOrchardServices _services;
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IBlogPathConstraint _blogPathConstraint;
private readonly IFeedManager _feedManager;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IHomePageProvider _routableHomePageProvider;
@@ -30,7 +30,7 @@ namespace Orchard.Blogs.Controllers {
IOrchardServices services,
IBlogService blogService,
IBlogPostService blogPostService,
IBlogSlugConstraint blogSlugConstraint,
IBlogPathConstraint blogPathConstraint,
IFeedManager feedManager,
IShapeFactory shapeFactory,
IWorkContextAccessor workContextAccessor,
@@ -39,7 +39,7 @@ namespace Orchard.Blogs.Controllers {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_blogSlugConstraint = blogSlugConstraint;
_blogPathConstraint = blogPathConstraint;
_feedManager = feedManager;
_workContextAccessor = workContextAccessor;
_siteService = siteService;
@@ -64,13 +64,13 @@ namespace Orchard.Blogs.Controllers {
return View((object)viewModel);
}
public ActionResult Item(string blogSlug, PagerParameters pagerParameters) {
public ActionResult Item(string blogPath, PagerParameters pagerParameters) {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var correctedSlug = _blogSlugConstraint.FindSlug(blogSlug);
if (correctedSlug == null)
var correctedPath = _blogPathConstraint.FindPath(blogPath);
if (correctedPath == null)
return HttpNotFound();
var blogPart = _blogService.Get(correctedSlug);
var blogPart = _blogService.Get(correctedPath);
if (blogPart == null)
return HttpNotFound();

View File

@@ -36,12 +36,12 @@ namespace Orchard.Blogs.Controllers {
public Localizer T { get; set; }
//TODO: (erikpo) Should think about moving the slug parameters and get calls and null checks up into a model binder or action filter
public ActionResult Item(string blogSlug, string postSlug) {
public ActionResult Item(string blogPath, string postSlug) {
if (!_services.Authorizer.Authorize(StandardPermissions.AccessFrontEnd, T("Couldn't view blog post")))
return new HttpUnauthorizedResult();
//TODO: (erikpo) Move looking up the current blog up into a modelbinder
var blogPart = _blogService.Get(blogSlug);
var blogPart = _blogService.Get(blogPath);
if (blogPart == null)
return HttpNotFound();
@@ -55,9 +55,9 @@ namespace Orchard.Blogs.Controllers {
return View((object)model);
}
public ActionResult ListByArchive(string blogSlug, string archiveData) {
public ActionResult ListByArchive(string blogPath, string archiveData) {
//TODO: (erikpo) Move looking up the current blog up into a modelbinder
BlogPart blogPart = _blogService.Get(blogSlug);
BlogPart blogPart = _blogService.Get(blogPath);
if (blogPart == null)
return HttpNotFound();

View File

@@ -21,10 +21,10 @@ namespace Orchard.Blogs.Controllers {
protected ILogger Logger { get; set; }
public ActionResult Rsd(string blogSlug) {
public ActionResult Rsd(string blogPath) {
Logger.Debug("RSD requested");
BlogPart blogPart = _blogService.Get(blogSlug);
BlogPart blogPart = _blogService.Get(blogPath);
if (blogPart == null)
return HttpNotFound();

View File

@@ -1,5 +1,6 @@
using System.Linq;
using Orchard.Blogs.Models;
using Orchard.Blogs.Routing;
using Orchard.Blogs.Services;
using Orchard.Blogs.ViewModels;
using Orchard.ContentManagement;
@@ -9,18 +10,22 @@ namespace Orchard.Blogs.Drivers {
public class BlogArchivesPartDriver : ContentPartDriver<BlogArchivesPart> {
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IBlogPathConstraint _blogPathConstraint;
public BlogArchivesPartDriver(IBlogService blogService, IBlogPostService blogPostService) {
public BlogArchivesPartDriver(
IBlogService blogService,
IBlogPostService blogPostService,
IBlogPathConstraint blogPathConstraint) {
_blogService = blogService;
_blogPostService = blogPostService;
_blogPathConstraint = blogPathConstraint;
}
protected override DriverResult Display(BlogArchivesPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Blogs_BlogArchives",
() => {
BlogPart blog = null;
if (!string.IsNullOrWhiteSpace(part.ForBlog))
blog = _blogService.Get(part.ForBlog);
var path = _blogPathConstraint.FindPath(part.ForBlog);
BlogPart blog = _blogService.Get(path);
if (blog == null)
return null;
@@ -31,7 +36,7 @@ namespace Orchard.Blogs.Drivers {
protected override DriverResult Editor(BlogArchivesPart part, dynamic shapeHelper) {
var viewModel = new BlogArchivesViewModel {
Slug = part.ForBlog,
Path = part.ForBlog,
Blogs = _blogService.Get().ToList().OrderBy(b => b.Name)
};
@@ -42,7 +47,7 @@ namespace Orchard.Blogs.Drivers {
protected override DriverResult Editor(BlogArchivesPart part, IUpdateModel updater, dynamic shapeHelper) {
var viewModel = new BlogArchivesViewModel();
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
part.ForBlog = viewModel.Slug;
part.ForBlog = viewModel.Path;
}
return Editor(part, shapeHelper);

View File

@@ -16,7 +16,7 @@ namespace Orchard.Blogs.Extensions {
}
public static string Blog(this UrlHelper urlHelper, BlogPart blogPart) {
return urlHelper.Action("Item", "Blog", new { blogSlug = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" });
return urlHelper.Action("Item", "Blog", new { blogPath = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" });
}
public static string BlogLiveWriterManifest(this UrlHelper urlHelper, BlogPart blogPart) {
@@ -24,19 +24,19 @@ namespace Orchard.Blogs.Extensions {
}
public static string BlogRsd(this UrlHelper urlHelper, BlogPart blogPart) {
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "RemoteBlogPublishing", new { blogSlug = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" }));
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "RemoteBlogPublishing", new { blogPath = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" }));
}
public static string BlogArchiveYear(this UrlHelper urlHelper, BlogPart blogPart, int year) {
return urlHelper.Action("ListByArchive", "BlogPost", new { blogSlug = blogPart.As<IRoutableAspect>().Path, archiveData = year.ToString(), area = "Orchard.Blogs" });
return urlHelper.Action("ListByArchive", "BlogPost", new { blogPath = blogPart.As<IRoutableAspect>().Path, archiveData = year.ToString(), area = "Orchard.Blogs" });
}
public static string BlogArchiveMonth(this UrlHelper urlHelper, BlogPart blogPart, int year, int month) {
return urlHelper.Action("ListByArchive", "BlogPost", new { blogSlug = blogPart.As<IRoutableAspect>().Path, archiveData = string.Format("{0}/{1}", year, month), area = "Orchard.Blogs" });
return urlHelper.Action("ListByArchive", "BlogPost", new { blogPath = blogPart.As<IRoutableAspect>().Path, archiveData = string.Format("{0}/{1}", year, month), area = "Orchard.Blogs" });
}
public static string BlogArchiveDay(this UrlHelper urlHelper, BlogPart blogPart, int year, int month, int day) {
return urlHelper.Action("ListByArchive", "BlogPost", new { blogSlug = blogPart.As<IRoutableAspect>().Path, archiveData = string.Format("{0}/{1}/{2}", year, month, day), area = "Orchard.Blogs" });
return urlHelper.Action("ListByArchive", "BlogPost", new { blogPath = blogPart.As<IRoutableAspect>().Path, archiveData = string.Format("{0}/{1}/{2}", year, month, day), area = "Orchard.Blogs" });
}
public static string BlogForAdmin(this UrlHelper urlHelper, BlogPart blogPart) {
@@ -60,7 +60,7 @@ namespace Orchard.Blogs.Extensions {
}
public static string BlogPost(this UrlHelper urlHelper, BlogPostPart blogPostPart) {
return urlHelper.Action("Item", "BlogPost", new { blogSlug = blogPostPart.BlogPart.As<IRoutableAspect>().Path, postSlug = blogPostPart.As<IRoutableAspect>().GetEffectiveSlug(), area = "Orchard.Blogs" });
return urlHelper.Action("Item", "BlogPost", new { blogPath = blogPostPart.BlogPart.As<IRoutableAspect>().Path, postSlug = blogPostPart.As<IRoutableAspect>().GetEffectiveSlug(), area = "Orchard.Blogs" });
}
public static string BlogPostEdit(this UrlHelper urlHelper, BlogPostPart blogPostPart) {

View File

@@ -16,22 +16,22 @@ namespace Orchard.Blogs.Handlers {
[UsedImplicitly]
public class BlogPartHandler : ContentHandler {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IBlogPathConstraint _blogPathConstraint;
private readonly IHomePageProvider _routableHomePageProvider;
public BlogPartHandler(IRepository<BlogPartRecord> repository, IWorkContextAccessor workContextAccessor, IEnumerable<IHomePageProvider> homePageProviders, IBlogSlugConstraint blogSlugConstraint) {
public BlogPartHandler(IRepository<BlogPartRecord> repository, IWorkContextAccessor workContextAccessor, IEnumerable<IHomePageProvider> homePageProviders, IBlogPathConstraint blogPathConstraint) {
_workContextAccessor = workContextAccessor;
_blogSlugConstraint = blogSlugConstraint;
_blogPathConstraint = blogPathConstraint;
_routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
Filters.Add(StorageFilter.For(repository));
Action<PublishContentContext, RoutePart> publishedHandler = (context, route) => {
if (route.Is<BlogPart>()) {
if (route.ContentItem.Id != 0 && route.PromoteToHomePage)
_blogSlugConstraint.AddSlug("");
_blogPathConstraint.AddPath("");
}
else if (route.ContentItem.Id != 0 && route.PromoteToHomePage) {
_blogSlugConstraint.RemoveSlug("");
_blogPathConstraint.RemovePath("");
}
};

View File

@@ -6,10 +6,10 @@ using Orchard.Mvc.Routes;
namespace Orchard.Blogs {
public class Routes : IRouteProvider {
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IBlogPathConstraint _blogPathConstraint;
public Routes(IBlogSlugConstraint blogSlugConstraint) {
_blogSlugConstraint = blogSlugConstraint;
public Routes(IBlogPathConstraint blogPathConstraint) {
_blogPathConstraint = blogPathConstraint;
}
public void GetRoutes(ICollection<RouteDescriptor> routes) {
@@ -175,14 +175,31 @@ namespace Orchard.Blogs {
},
new RouteDescriptor {
Route = new Route(
"{blogSlug}/Archive/{*archiveData}",
"Archive/{*archiveData}",
new RouteValueDictionary {
{"blogPath", ""},
{"area", "Orchard.Blogs"},
{"controller", "BlogPost"},
{"action", "ListByArchive"}
},
new RouteValueDictionary {
{"archiveData", new IsArchiveConstraint()}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"{blogPath}/Archive/{*archiveData}",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPost"},
{"action", "ListByArchive"}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint},
{"blogPath", _blogPathConstraint},
{"archiveData", new IsArchiveConstraint()}
},
new RouteValueDictionary {
@@ -193,14 +210,14 @@ namespace Orchard.Blogs {
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogSlug}/rsd",
"{blogPath}/rsd",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "RemoteBlogPublishing"},
{"action", "Rsd"}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint}
{"blogPath", _blogPathConstraint}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
@@ -210,14 +227,14 @@ namespace Orchard.Blogs {
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogSlug}/{postSlug}",
"{blogPath}/{postSlug}",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPost"},
{"action", "Item"}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint}
{"blogPath", _blogPathConstraint}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
@@ -227,15 +244,15 @@ namespace Orchard.Blogs {
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogSlug}",
"{blogPath}",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "Blog"},
{"action", "Item"},
{"blogSlug", ""}
{"blogPath", ""}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint}
{"blogPath", _blogPathConstraint}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}

View File

@@ -8,46 +8,55 @@ using Orchard.Logging;
namespace Orchard.Blogs.Routing {
[UsedImplicitly]
public class BlogSlugConstraint : IBlogSlugConstraint {
public class BlogPathConstraint : IBlogPathConstraint {
/// <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>();
private IDictionary<string, string> _paths = new Dictionary<string, string>();
public BlogSlugConstraint() {
public BlogPathConstraint() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SetSlugs(IEnumerable<string> slugs) {
public void SetPaths(IEnumerable<string> paths) {
// Make a copy to avoid performing potential lazy computation inside the lock
var slugsArray = slugs.ToArray();
var pathArray = paths.ToArray();
lock (_syncLock) {
_slugs = slugsArray.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
_paths = pathArray.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
}
Logger.Debug("Blog slugs: {0}", string.Join(", ", slugsArray));
Logger.Debug("Blog paths: {0}", string.Join(", ", pathArray));
}
public string FindSlug(string slug) {
public string FindPath(string path) {
lock (_syncLock) {
string actual;
return _slugs.TryGetValue(slug, out actual) ? actual : slug;
// path can be null for homepage
path = path ?? "";
return _paths.TryGetValue(path, out actual) ? actual : path;
}
}
public void AddSlug(string slug) {
public void AddPath(string path) {
lock (_syncLock) {
_slugs[slug] = slug;
// path can be null for homepage
path = path ?? "";
_paths[path] = path;
}
}
public void RemoveSlug(string slug) {
public void RemovePath(string path) {
lock (_syncLock) {
_slugs.Remove(slug);
// path can be null for homepage
path = path ?? "";
_paths.Remove(path);
}
}
@@ -60,7 +69,7 @@ namespace Orchard.Blogs.Routing {
var parameterValue = Convert.ToString(value);
lock (_syncLock) {
return _slugs.ContainsKey(parameterValue);
return _paths.ContainsKey(parameterValue);
}
}

View File

@@ -8,12 +8,12 @@ using Orchard.Tasks;
namespace Orchard.Blogs.Routing {
[UsedImplicitly]
public class BlogSlugConstraintUpdator : IOrchardShellEvents, IBackgroundTask {
private readonly IBlogSlugConstraint _blogSlugConstraint;
public class BlogPathConstraintUpdator : IOrchardShellEvents, IBackgroundTask {
private readonly IBlogPathConstraint _blogPathConstraint;
private readonly IBlogService _blogService;
public BlogSlugConstraintUpdator(IBlogSlugConstraint blogSlugConstraint, IBlogService blogService) {
_blogSlugConstraint = blogSlugConstraint;
public BlogPathConstraintUpdator(IBlogPathConstraint blogPathConstraint, IBlogService blogService) {
_blogPathConstraint = blogPathConstraint;
_blogService = blogService;
}
@@ -29,7 +29,7 @@ namespace Orchard.Blogs.Routing {
}
private void Refresh() {
_blogSlugConstraint.SetSlugs(_blogService.Get().Select(b => b.As<IRoutableAspect>().Path));
_blogPathConstraint.SetPaths(_blogService.Get().Select(b => b.As<IRoutableAspect>().Slug));
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Web.Routing;
namespace Orchard.Blogs.Routing {
public interface IBlogPathConstraint : IRouteConstraint, ISingletonDependency {
void SetPaths(IEnumerable<string> paths);
string FindPath(string path);
void AddPath(string path);
void RemovePath(string path);
}
}

View File

@@ -1,11 +0,0 @@
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);
}
}

View File

@@ -29,9 +29,9 @@ namespace Orchard.Blogs.Services {
}
public BlogPostPart Get(BlogPart blogPart, string slug, VersionOptions versionOptions) {
var postSlug = blogPart.As<IRoutableAspect>().GetChildPath(slug);
var postPath = blogPart.As<IRoutableAspect>().GetChildPath(slug);
return
_contentManager.Query(versionOptions, "BlogPost").Join<RoutePartRecord>().Where(rr => rr.Path == postSlug).
_contentManager.Query(versionOptions, "BlogPost").Join<RoutePartRecord>().Where(rr => rr.Path == postPath).
Join<CommonPartRecord>().Where(cr => cr.Container == blogPart.Record.ContentItemRecord).List().
SingleOrDefault().As<BlogPostPart>();
}

View File

@@ -11,11 +11,11 @@ namespace Orchard.Blogs.Services {
[UsedImplicitly]
public class BlogService : IBlogService {
private readonly IContentManager _contentManager;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IBlogPathConstraint _blogPathConstraint;
public BlogService(IContentManager contentManager, IBlogSlugConstraint blogSlugConstraint) {
public BlogService(IContentManager contentManager, IBlogPathConstraint blogPathConstraint) {
_contentManager = contentManager;
_blogSlugConstraint = blogSlugConstraint;
_blogPathConstraint = blogPathConstraint;
}
public BlogPart Get(string path) {
@@ -39,9 +39,15 @@ namespace Orchard.Blogs.Services {
.List();
}
public BlogPart GetFromSlug(string slug) {
return _contentManager.Query<BlogPart, BlogPartRecord>()
.Join<RoutePartRecord>().Where(rr => rr.Slug == slug)
.List().FirstOrDefault();
}
public void Delete(ContentItem blog) {
_contentManager.Remove(blog);
_blogSlugConstraint.RemoveSlug(blog.As<IRoutableAspect>().Path);
_blogPathConstraint.RemovePath(blog.As<IRoutableAspect>().Path);
}
}
}

View File

@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Generic;
using Orchard.Blogs.Models;
namespace Orchard.Blogs.ViewModels {
public class BlogArchivesViewModel {
public string Slug { get; set; }
public string Path { get; set; }
public IEnumerable<BlogPart> Blogs { get; set; }
}
}