mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Merge
--HG-- branch : autoroute
This commit is contained in:
+6
-6
@@ -1,9 +1,9 @@
|
|||||||
d91108343ff1259cd3e35b2c080eb166d024711b src/Orchard.Web/Modules/Orchard.Alias
|
81cb672c85fd980dd3db0515544b79a918e5eb69 src/Orchard.Web/Modules/Orchard.Alias
|
||||||
547b36a689a1f75c90eba578e6c409cf4be62a92 src/Orchard.Web/Modules/Orchard.Autoroute
|
240a2fcf69c5c94e8da6dfb1bc2c8e7d45e6554b src/Orchard.Web/Modules/Orchard.Autoroute
|
||||||
67bf9897ee9dd9483369aece729ad7c6f042941c src/Orchard.Web/Modules/Orchard.Forms
|
c54cb640d6bc14c51b9fb9bd78231bb0facec067 src/Orchard.Web/Modules/Orchard.Forms
|
||||||
6033664adc404a22f311029b69fbf1e34dc4ff2a src/Orchard.Web/Modules/Orchard.Projections
|
c27801666ed3e8f9b9c7979a837e7d770763352a src/Orchard.Web/Modules/Orchard.Projections
|
||||||
a1ef39ba4e2d0cd78b3c91d6150e841793acb34b src/Orchard.Web/Modules/Orchard.Routable
|
a1ef39ba4e2d0cd78b3c91d6150e841793acb34b src/Orchard.Web/Modules/Orchard.Routable
|
||||||
204bdef384f41bb5e463bed6b98a056945a7d839 src/Orchard.Web/Modules/Orchard.Rules
|
204bdef384f41bb5e463bed6b98a056945a7d839 src/Orchard.Web/Modules/Orchard.Rules
|
||||||
ce578373f907c0a55fd91229a344f0755f290174 src/Orchard.Web/Modules/Orchard.TaskLease
|
ce578373f907c0a55fd91229a344f0755f290174 src/Orchard.Web/Modules/Orchard.TaskLease
|
||||||
5e7ce95ca5ab364401cad3e220e1429bfed847db src/Orchard.Web/Modules/Orchard.Tokens
|
5910b8af112fc7911456144bf83cb9a5d6ae8067 src/Orchard.Web/Modules/Orchard.Tokens
|
||||||
1babbc24ce7e890ec95755c992c14c9ff4ed448d src/orchard.web/modules/Orchard.Fields
|
f0cbc5b3e84358940345fa9653c0c11e3aad0b12 src/orchard.web/modules/Orchard.Fields
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.Blogs.Extensions;
|
using Orchard.Blogs.Extensions;
|
||||||
using Orchard.Blogs.Models;
|
using Orchard.Blogs.Models;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.Blogs.Services;
|
using Orchard.Blogs.Services;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.Aspects;
|
|
||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
using Orchard.DisplayManagement;
|
using Orchard.DisplayManagement;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.Blogs.Extensions;
|
using Orchard.Blogs.Extensions;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.Blogs.Services;
|
using Orchard.Blogs.Services;
|
||||||
using Orchard.Core.Feeds;
|
using Orchard.Core.Feeds;
|
||||||
using Orchard.DisplayManagement;
|
using Orchard.DisplayManagement;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
using Orchard.Mvc;
|
using Orchard.Mvc;
|
||||||
using Orchard.Services;
|
|
||||||
using Orchard.Themes;
|
using Orchard.Themes;
|
||||||
using Orchard.UI.Navigation;
|
using Orchard.UI.Navigation;
|
||||||
using Orchard.Settings;
|
using Orchard.Settings;
|
||||||
@@ -21,23 +20,23 @@ namespace Orchard.Blogs.Controllers {
|
|||||||
private readonly IOrchardServices _services;
|
private readonly IOrchardServices _services;
|
||||||
private readonly IBlogService _blogService;
|
private readonly IBlogService _blogService;
|
||||||
private readonly IBlogPostService _blogPostService;
|
private readonly IBlogPostService _blogPostService;
|
||||||
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
private readonly IFeedManager _feedManager;
|
private readonly IFeedManager _feedManager;
|
||||||
private readonly IWorkContextAccessor _workContextAccessor;
|
|
||||||
private readonly ISiteService _siteService;
|
private readonly ISiteService _siteService;
|
||||||
|
|
||||||
public BlogController(
|
public BlogController(
|
||||||
IOrchardServices services,
|
IOrchardServices services,
|
||||||
IBlogService blogService,
|
IBlogService blogService,
|
||||||
IBlogPostService blogPostService,
|
IBlogPostService blogPostService,
|
||||||
|
IBlogPathConstraint blogPathConstraint,
|
||||||
IFeedManager feedManager,
|
IFeedManager feedManager,
|
||||||
IShapeFactory shapeFactory,
|
IShapeFactory shapeFactory,
|
||||||
IWorkContextAccessor workContextAccessor,
|
|
||||||
ISiteService siteService) {
|
ISiteService siteService) {
|
||||||
_services = services;
|
_services = services;
|
||||||
_blogService = blogService;
|
_blogService = blogService;
|
||||||
_blogPostService = blogPostService;
|
_blogPostService = blogPostService;
|
||||||
|
_blogPathConstraint = blogPathConstraint;
|
||||||
_feedManager = feedManager;
|
_feedManager = feedManager;
|
||||||
_workContextAccessor = workContextAccessor;
|
|
||||||
_siteService = siteService;
|
_siteService = siteService;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
Shape = shapeFactory;
|
Shape = shapeFactory;
|
||||||
@@ -60,7 +59,6 @@ namespace Orchard.Blogs.Controllers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult Item(int blogId, PagerParameters pagerParameters) {
|
public ActionResult Item(int blogId, PagerParameters pagerParameters) {
|
||||||
// TODO: (PH:Autoroute) Should use Containers so we can lose this action and rely on ContainerPartDriver instead
|
|
||||||
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
||||||
|
|
||||||
var blogPart = _blogService.Get(blogId, VersionOptions.Published).As<BlogPart>();
|
var blogPart = _blogService.Get(blogId, VersionOptions.Published).As<BlogPart>();
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ using System.Linq;
|
|||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using Orchard.Blogs.Extensions;
|
using Orchard.Blogs.Extensions;
|
||||||
using Orchard.Blogs.Models;
|
using Orchard.Blogs.Models;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.Blogs.Services;
|
using Orchard.Blogs.Services;
|
||||||
using Orchard.ContentManagement;
|
|
||||||
using Orchard.Core.Feeds;
|
using Orchard.Core.Feeds;
|
||||||
using Orchard.DisplayManagement;
|
using Orchard.DisplayManagement;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
using Orchard.Mvc;
|
|
||||||
using Orchard.Security;
|
|
||||||
using Orchard.Themes;
|
using Orchard.Themes;
|
||||||
|
|
||||||
namespace Orchard.Blogs.Controllers {
|
namespace Orchard.Blogs.Controllers {
|
||||||
@@ -18,17 +16,20 @@ namespace Orchard.Blogs.Controllers {
|
|||||||
private readonly IBlogService _blogService;
|
private readonly IBlogService _blogService;
|
||||||
private readonly IBlogPostService _blogPostService;
|
private readonly IBlogPostService _blogPostService;
|
||||||
private readonly IFeedManager _feedManager;
|
private readonly IFeedManager _feedManager;
|
||||||
|
private readonly IArchiveConstraint _archiveConstraint;
|
||||||
|
|
||||||
public BlogPostController(
|
public BlogPostController(
|
||||||
IOrchardServices services,
|
IOrchardServices services,
|
||||||
IBlogService blogService,
|
IBlogService blogService,
|
||||||
IBlogPostService blogPostService,
|
IBlogPostService blogPostService,
|
||||||
IFeedManager feedManager,
|
IFeedManager feedManager,
|
||||||
IShapeFactory shapeFactory) {
|
IShapeFactory shapeFactory,
|
||||||
|
IArchiveConstraint archiveConstraint) {
|
||||||
_services = services;
|
_services = services;
|
||||||
_blogService = blogService;
|
_blogService = blogService;
|
||||||
_blogPostService = blogPostService;
|
_blogPostService = blogPostService;
|
||||||
_feedManager = feedManager;
|
_feedManager = feedManager;
|
||||||
|
_archiveConstraint = archiveConstraint;
|
||||||
T = NullLocalizer.Instance;
|
T = NullLocalizer.Instance;
|
||||||
Shape = shapeFactory;
|
Shape = shapeFactory;
|
||||||
}
|
}
|
||||||
@@ -36,15 +37,22 @@ namespace Orchard.Blogs.Controllers {
|
|||||||
dynamic Shape { get; set; }
|
dynamic Shape { get; set; }
|
||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
public ActionResult ListByArchive(int blogId, string archiveData) {
|
public ActionResult ListByArchive(string path) {
|
||||||
//TODO: (erikpo) Move looking up the current blog up into a modelbinder
|
|
||||||
BlogPart blogPart = _blogService.Get(blogId,VersionOptions.Published).As<BlogPart>();
|
var blogPath = _archiveConstraint.FindPath(path);
|
||||||
|
var archive = _archiveConstraint.FindArchiveData(path);
|
||||||
|
|
||||||
|
if (blogPath == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
if (archive == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
BlogPart blogPart = _blogService.Get(blogPath);
|
||||||
|
|
||||||
if (blogPart == null)
|
if (blogPart == null)
|
||||||
return HttpNotFound();
|
return HttpNotFound();
|
||||||
|
|
||||||
var archive = new ArchiveData(archiveData);
|
|
||||||
|
|
||||||
var list = Shape.List();
|
var list = Shape.List();
|
||||||
list.AddRange(_blogPostService.Get(blogPart, archive).Select(b => _services.ContentManager.BuildDisplay(b, "Summary")));
|
list.AddRange(_blogPostService.Get(blogPart, archive).Select(b => _services.ContentManager.BuildDisplay(b, "Summary")));
|
||||||
|
|
||||||
|
|||||||
+15
-3
@@ -3,6 +3,7 @@ using System.Web.Mvc;
|
|||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Orchard.Blogs.Models;
|
using Orchard.Blogs.Models;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.Blogs.Services;
|
using Orchard.Blogs.Services;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
@@ -12,20 +13,31 @@ namespace Orchard.Blogs.Controllers {
|
|||||||
[OrchardFeature("Orchard.Blogs.RemotePublishing")]
|
[OrchardFeature("Orchard.Blogs.RemotePublishing")]
|
||||||
public class RemoteBlogPublishingController : Controller {
|
public class RemoteBlogPublishingController : Controller {
|
||||||
private readonly IBlogService _blogService;
|
private readonly IBlogService _blogService;
|
||||||
|
private readonly IRsdConstraint _rsdConstraint;
|
||||||
private readonly RouteCollection _routeCollection;
|
private readonly RouteCollection _routeCollection;
|
||||||
|
|
||||||
public RemoteBlogPublishingController(IOrchardServices services, IBlogService blogService, RouteCollection routeCollection) {
|
public RemoteBlogPublishingController(
|
||||||
|
IOrchardServices services,
|
||||||
|
IBlogService blogService,
|
||||||
|
IRsdConstraint rsdConstraint,
|
||||||
|
RouteCollection routeCollection) {
|
||||||
_blogService = blogService;
|
_blogService = blogService;
|
||||||
|
_rsdConstraint = rsdConstraint;
|
||||||
_routeCollection = routeCollection;
|
_routeCollection = routeCollection;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ILogger Logger { get; set; }
|
protected ILogger Logger { get; set; }
|
||||||
|
|
||||||
public ActionResult Rsd(int blogId) {
|
public ActionResult Rsd(string path) {
|
||||||
Logger.Debug("RSD requested");
|
Logger.Debug("RSD requested");
|
||||||
|
|
||||||
BlogPart blogPart = _blogService.Get(blogId);
|
var blogPath = _rsdConstraint.FindPath(path);
|
||||||
|
|
||||||
|
if (blogPath == null)
|
||||||
|
return HttpNotFound();
|
||||||
|
|
||||||
|
BlogPart blogPart = _blogService.Get(blogPath);
|
||||||
|
|
||||||
if (blogPart == null)
|
if (blogPart == null)
|
||||||
return HttpNotFound();
|
return HttpNotFound();
|
||||||
|
|||||||
@@ -5,21 +5,17 @@ using Orchard.Blogs.ViewModels;
|
|||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.Drivers;
|
using Orchard.ContentManagement.Drivers;
|
||||||
using Orchard.ContentManagement.Handlers;
|
using Orchard.ContentManagement.Handlers;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Orchard.Blogs.Drivers {
|
namespace Orchard.Blogs.Drivers {
|
||||||
public class BlogArchivesPartDriver : ContentPartDriver<BlogArchivesPart> {
|
public class BlogArchivesPartDriver : ContentPartDriver<BlogArchivesPart> {
|
||||||
private readonly IBlogService _blogService;
|
private readonly IBlogService _blogService;
|
||||||
private readonly IBlogPostService _blogPostService;
|
private readonly IBlogPostService _blogPostService;
|
||||||
private readonly IContentManager _contentManager;
|
|
||||||
|
|
||||||
public BlogArchivesPartDriver(
|
public BlogArchivesPartDriver(
|
||||||
IBlogService blogService,
|
IBlogService blogService,
|
||||||
IBlogPostService blogPostService,
|
IBlogPostService blogPostService) {
|
||||||
IContentManager contentManager) {
|
|
||||||
_blogService = blogService;
|
_blogService = blogService;
|
||||||
_blogPostService = blogPostService;
|
_blogPostService = blogPostService;
|
||||||
_contentManager = contentManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DriverResult Display(BlogArchivesPart part, string displayType, dynamic shapeHelper) {
|
protected override DriverResult Display(BlogArchivesPart part, string displayType, dynamic shapeHelper) {
|
||||||
@@ -36,7 +32,7 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
|
|
||||||
protected override DriverResult Editor(BlogArchivesPart part, dynamic shapeHelper) {
|
protected override DriverResult Editor(BlogArchivesPart part, dynamic shapeHelper) {
|
||||||
var viewModel = new BlogArchivesViewModel {
|
var viewModel = new BlogArchivesViewModel {
|
||||||
BlogId = part.ForBlog,
|
Slug = part.ForBlog,
|
||||||
Blogs = _blogService.Get().ToList().OrderBy(b => b.Name)
|
Blogs = _blogService.Get().ToList().OrderBy(b => b.Name)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,21 +43,21 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
protected override DriverResult Editor(BlogArchivesPart part, IUpdateModel updater, dynamic shapeHelper) {
|
protected override DriverResult Editor(BlogArchivesPart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||||
var viewModel = new BlogArchivesViewModel();
|
var viewModel = new BlogArchivesViewModel();
|
||||||
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
|
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
|
||||||
part.ForBlog = viewModel.BlogId;
|
part.ForBlog = viewModel.Slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Editor(part, shapeHelper);
|
return Editor(part, shapeHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Importing(BlogArchivesPart part, ImportContentContext context) {
|
protected override void Importing(BlogArchivesPart part, ImportContentContext context) {
|
||||||
var blogId = context.Attribute(part.PartDefinition.Name, "BlogId");
|
var blogSlug = context.Attribute(part.PartDefinition.Name, "BlogSlug");
|
||||||
if (blogId != null) {
|
if (blogSlug != null) {
|
||||||
part.ForBlog = Convert.ToInt32(blogId);
|
part.ForBlog = blogSlug;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Exporting(BlogArchivesPart part, ExportContentContext context) {
|
protected override void Exporting(BlogArchivesPart part, ExportContentContext context) {
|
||||||
context.Element(part.PartDefinition.Name).SetAttributeValue("BlogId", part.ForBlog);
|
context.Element(part.PartDefinition.Name).SetAttributeValue("BlogSlug", part.ForBlog);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
protected override DriverResult Editor(RecentBlogPostsPart part, dynamic shapeHelper) {
|
protected override DriverResult Editor(RecentBlogPostsPart part, dynamic shapeHelper) {
|
||||||
var viewModel = new RecentBlogPostsViewModel {
|
var viewModel = new RecentBlogPostsViewModel {
|
||||||
Count = part.Count,
|
Count = part.Count,
|
||||||
BlogId = part.ForBlog,
|
Slug = part.ForBlog,
|
||||||
Blogs = _blogService.Get().ToList().OrderBy(b => b.Name)
|
Blogs = _blogService.Get().ToList().OrderBy(b => b.Name)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
protected override DriverResult Editor(RecentBlogPostsPart part, IUpdateModel updater, dynamic shapeHelper) {
|
protected override DriverResult Editor(RecentBlogPostsPart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||||
var viewModel = new RecentBlogPostsViewModel();
|
var viewModel = new RecentBlogPostsViewModel();
|
||||||
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
|
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
|
||||||
part.ForBlog = viewModel.BlogId;
|
part.ForBlog = viewModel.Slug;
|
||||||
part.Count = viewModel.Count;
|
part.Count = viewModel.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,9 +65,9 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void Importing(RecentBlogPostsPart part, ImportContentContext context) {
|
protected override void Importing(RecentBlogPostsPart part, ImportContentContext context) {
|
||||||
var blogId = context.Attribute(part.PartDefinition.Name, "BlogId");
|
var blogSlug = context.Attribute(part.PartDefinition.Name, "BlogSlug");
|
||||||
if (blogId != null) {
|
if (blogSlug != null) {
|
||||||
part.ForBlog = Convert.ToInt32(blogId);
|
part.ForBlog = blogSlug;
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = context.Attribute(part.PartDefinition.Name, "Count");
|
var count = context.Attribute(part.PartDefinition.Name, "Count");
|
||||||
@@ -77,9 +77,8 @@ namespace Orchard.Blogs.Drivers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void Exporting(RecentBlogPostsPart part, ExportContentContext context) {
|
protected override void Exporting(RecentBlogPostsPart part, ExportContentContext context) {
|
||||||
context.Element(part.PartDefinition.Name).SetAttributeValue("BlogId", part.ForBlog);
|
context.Element(part.PartDefinition.Name).SetAttributeValue("BlogSlug", part.ForBlog);
|
||||||
context.Element(part.PartDefinition.Name).SetAttributeValue("Count", part.Count);
|
context.Element(part.PartDefinition.Name).SetAttributeValue("Count", part.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@ using Orchard.Blogs.Models;
|
|||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.Aspects;
|
using Orchard.ContentManagement.Aspects;
|
||||||
using Orchard.Mvc.Extensions;
|
using Orchard.Mvc.Extensions;
|
||||||
using Orchard.Mvc.Html;
|
|
||||||
|
|
||||||
namespace Orchard.Blogs.Extensions {
|
namespace Orchard.Blogs.Extensions {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,19 +26,19 @@ namespace Orchard.Blogs.Extensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static string BlogRsd(this UrlHelper urlHelper, BlogPart blogPart) {
|
public static string BlogRsd(this UrlHelper urlHelper, BlogPart blogPart) {
|
||||||
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "RemoteBlogPublishing", new { blogId = blogPart.ContentItem.Id, area = "Orchard.Blogs" }));
|
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "RemoteBlogPublishing", new { path = blogPart.As<IAliasAspect>().Path + "/rsd", area = "Orchard.Blogs" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string BlogArchiveYear(this UrlHelper urlHelper, BlogPart blogPart, int year) {
|
public static string BlogArchiveYear(this UrlHelper urlHelper, BlogPart blogPart, int year) {
|
||||||
return urlHelper.Action("ListByArchive", "BlogPost", new { blogId = blogPart.ContentItem.Id, archiveData = year.ToString(), area = "Orchard.Blogs" });
|
return urlHelper.Action("ListByArchive", "BlogPost", new { path = blogPart.As<IAliasAspect>().Path + "/archive/" + year.ToString(), area = "Orchard.Blogs" });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string BlogArchiveMonth(this UrlHelper urlHelper, BlogPart blogPart, int year, int month) {
|
public static string BlogArchiveMonth(this UrlHelper urlHelper, BlogPart blogPart, int year, int month) {
|
||||||
return urlHelper.Action("ListByArchive", "BlogPost", new { blogId = blogPart.ContentItem.Id, archiveData = string.Format("{0:0000}/{1:00}", year, month), area = "Orchard.Blogs" });
|
return urlHelper.Action("ListByArchive", "BlogPost", new { path = blogPart.As<IAliasAspect>().Path + "/archive/" + string.Format("{0}/{1}", year, month), area = "Orchard.Blogs" });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string BlogArchiveDay(this UrlHelper urlHelper, BlogPart blogPart, int year, int month, int day) {
|
public static string BlogArchiveDay(this UrlHelper urlHelper, BlogPart blogPart, int year, int month, int day) {
|
||||||
return urlHelper.Action("ListByArchive", "BlogPost", new { blogId = blogPart.ContentItem.Id, archiveData = string.Format("{0:0000}/{1:00}/{2:00}", year, month, day), area = "Orchard.Blogs" });
|
return urlHelper.Action("ListByArchive", "BlogPost", new { path = blogPart.As<IAliasAspect>().Path + "/archive/" + string.Format("{0}/{1}/{2}", year, month, day), area = "Orchard.Blogs" });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string BlogForAdmin(this UrlHelper urlHelper, BlogPart blogPart) {
|
public static string BlogForAdmin(this UrlHelper urlHelper, BlogPart blogPart) {
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Orchard.Blogs.Models;
|
using Orchard.Blogs.Models;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Aspects;
|
||||||
using Orchard.ContentManagement.Handlers;
|
using Orchard.ContentManagement.Handlers;
|
||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
using Orchard.Services;
|
|
||||||
|
|
||||||
namespace Orchard.Blogs.Handlers {
|
namespace Orchard.Blogs.Handlers {
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class BlogPartHandler : ContentHandler {
|
public class BlogPartHandler : ContentHandler {
|
||||||
private readonly IWorkContextAccessor _workContextAccessor;
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
|
|
||||||
public BlogPartHandler(IRepository<BlogPartRecord> repository, IWorkContextAccessor workContextAccessor) {
|
public BlogPartHandler(IRepository<BlogPartRecord> repository, IBlogPathConstraint blogPathConstraint) {
|
||||||
_workContextAccessor = workContextAccessor;
|
_blogPathConstraint = blogPathConstraint;
|
||||||
Filters.Add(StorageFilter.For(repository));
|
Filters.Add(StorageFilter.For(repository));
|
||||||
|
|
||||||
OnGetDisplayShape<BlogPart>((context, blog) => {
|
OnGetDisplayShape<BlogPart>((context, blog) => {
|
||||||
context.Shape.Description = blog.Description;
|
context.Shape.Description = blog.Description;
|
||||||
context.Shape.PostCount = blog.PostCount;
|
context.Shape.PostCount = blog.PostCount;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
OnPublished<BlogPart>((context, blog) => _blogPathConstraint.AddPath(blog.As<IAliasAspect>().Path));
|
||||||
|
OnUnpublished<BlogPart>((context, blog) => _blogPathConstraint.RemovePath(blog.As<IAliasAspect>().Path));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
|
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ namespace Orchard.Blogs.Handlers {
|
|||||||
if (blogPost == null)
|
if (blogPost == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Note: DisplayRouteValues are still inherited from CommonPart. We shouldn't even need these overrides for admin routes. -PH
|
|
||||||
|
|
||||||
context.Metadata.CreateRouteValues = new RouteValueDictionary {
|
context.Metadata.CreateRouteValues = new RouteValueDictionary {
|
||||||
{"Area", "Orchard.Blogs"},
|
{"Area", "Orchard.Blogs"},
|
||||||
{"Controller", "BlogPostAdmin"},
|
{"Controller", "BlogPostAdmin"},
|
||||||
|
|||||||
@@ -106,27 +106,8 @@ namespace Orchard.Blogs {
|
|||||||
.WithPart("TitlePart")
|
.WithPart("TitlePart")
|
||||||
.WithPart("AutoroutePart")
|
.WithPart("AutoroutePart")
|
||||||
);
|
);
|
||||||
|
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
public int UpdateFrom5() {
|
|
||||||
SchemaBuilder.AlterTable("RecentBlogPostsPartRecord",
|
|
||||||
table => table.AddColumn<int>("BlogId")
|
|
||||||
);
|
|
||||||
|
|
||||||
SchemaBuilder.AlterTable("BlogArchivesPartRecord",
|
|
||||||
table => table.AddColumn<int>("BlogId")
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: (PH:Autoroute) Convert BlogSlug to BlogId
|
|
||||||
SchemaBuilder.AlterTable("RecentBlogPostsPartRecord",
|
|
||||||
table => table.DropColumn("BlogSlug")
|
|
||||||
);
|
|
||||||
|
|
||||||
SchemaBuilder.AlterTable("BlogArchivesPartRecord",
|
|
||||||
table => table.DropColumn("BlogSlug")
|
|
||||||
);
|
|
||||||
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,9 +7,9 @@ namespace Orchard.Blogs.Models {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class BlogArchivesPart : ContentPart<BlogArchivesPartRecord> {
|
public class BlogArchivesPart : ContentPart<BlogArchivesPartRecord> {
|
||||||
[Required]
|
[Required]
|
||||||
public int ForBlog {
|
public string ForBlog {
|
||||||
get { return Record.BlogId; }
|
get { return Record.BlogSlug; }
|
||||||
set { Record.BlogId = value; }
|
set { Record.BlogSlug = value; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using Orchard.ContentManagement.Records;
|
||||||
using Orchard.ContentManagement.Records;
|
|
||||||
|
|
||||||
namespace Orchard.Blogs.Models {
|
namespace Orchard.Blogs.Models {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The content part used by the BlogArchives widget
|
/// The content part used by the BlogArchives widget
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BlogArchivesPartRecord : ContentPartRecord {
|
public class BlogArchivesPartRecord : ContentPartRecord {
|
||||||
public virtual int BlogId { get; set; }
|
public virtual string BlogSlug { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ namespace Orchard.Blogs.Models {
|
|||||||
public class RecentBlogPostsPart : ContentPart<RecentBlogPostsPartRecord> {
|
public class RecentBlogPostsPart : ContentPart<RecentBlogPostsPartRecord> {
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public int ForBlog {
|
public string ForBlog {
|
||||||
get { return Record.BlogId; }
|
get { return Record.BlogSlug; }
|
||||||
set { Record.BlogId = value; }
|
set { Record.BlogSlug = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ namespace Orchard.Blogs.Models {
|
|||||||
public RecentBlogPostsPartRecord() {
|
public RecentBlogPostsPartRecord() {
|
||||||
Count = 5;
|
Count = 5;
|
||||||
}
|
}
|
||||||
public virtual int BlogId { get; set; }
|
|
||||||
|
public virtual string BlogSlug { get; set; }
|
||||||
public virtual int Count { get; set; }
|
public virtual int Count { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ Features:
|
|||||||
Orchard.Blogs.RemotePublishing:
|
Orchard.Blogs.RemotePublishing:
|
||||||
Name: Remote Blog Publishing
|
Name: Remote Blog Publishing
|
||||||
Description: Blog easier using a dedicated MetaWeblogAPI-compatible publishing tool.
|
Description: Blog easier using a dedicated MetaWeblogAPI-compatible publishing tool.
|
||||||
Dependencies: XmlRpc, Orchard.Blogs
|
Dependencies: XmlRpc, Orchard.Blogs, Orchard.Autoroute
|
||||||
Category: Content Publishing
|
Category: Content Publishing
|
||||||
|
|||||||
@@ -79,7 +79,13 @@
|
|||||||
<Compile Include="Handlers\BlogPartArchiveHandler.cs" />
|
<Compile Include="Handlers\BlogPartArchiveHandler.cs" />
|
||||||
<Compile Include="Models\BlogPartArchiveRecord.cs" />
|
<Compile Include="Models\BlogPartArchiveRecord.cs" />
|
||||||
<Compile Include="Permissions.cs" />
|
<Compile Include="Permissions.cs" />
|
||||||
<Compile Include="Providers\BlogAutoroutes.cs" />
|
<Compile Include="Routing\BlogPathConstraint.cs" />
|
||||||
|
<Compile Include="Routing\BlogPathConstraintUpdator.cs" />
|
||||||
|
<Compile Include="Routing\ArchiveConstraint.cs" />
|
||||||
|
<Compile Include="Routing\IArchiveConstraint.cs" />
|
||||||
|
<Compile Include="Routing\RsdConstraint.cs" />
|
||||||
|
<Compile Include="Routing\IRsdConstraint.cs" />
|
||||||
|
<Compile Include="Routing\IBlogPathConstraint.cs" />
|
||||||
<Compile Include="Security\BlogAuthorizationEventHandler.cs" />
|
<Compile Include="Security\BlogAuthorizationEventHandler.cs" />
|
||||||
<Compile Include="Services\BlogService.cs" />
|
<Compile Include="Services\BlogService.cs" />
|
||||||
<Compile Include="Controllers\BlogController.cs" />
|
<Compile Include="Controllers\BlogController.cs" />
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Orchard.Events;
|
|
||||||
using System.Web.Routing;
|
|
||||||
using Orchard.ContentManagement;
|
|
||||||
using Orchard.Blogs.Models;
|
|
||||||
using Orchard.Core.Common.Models;
|
|
||||||
using Orchard.Localization;
|
|
||||||
|
|
||||||
namespace Orchard.Blogs.Providers {
|
|
||||||
|
|
||||||
|
|
||||||
public interface IRoutePatternProvider : IEventHandler {
|
|
||||||
void Describe(dynamic describe);
|
|
||||||
void Suggest(dynamic suggest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BlogAutoroutes : IRoutePatternProvider {
|
|
||||||
|
|
||||||
public BlogAutoroutes() {
|
|
||||||
T = NullLocalizer.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Localizer T { get; set; }
|
|
||||||
|
|
||||||
const string yearToken = "{Content.Date.Format:yyyy}";
|
|
||||||
const string monthToken = "{Content.Date.Format:MM}";
|
|
||||||
const string dayToken = "{Content.Date.Format:dd}";
|
|
||||||
const string idParentToken = "{Content.Container.Id}";
|
|
||||||
const string idToken = "{Content.Id}";
|
|
||||||
const string blogToken = "{Content.Slug}";
|
|
||||||
const string blogPostToken = "{Content.Container.Path}/{Content.Slug}";
|
|
||||||
|
|
||||||
public void Describe(dynamic describe) {
|
|
||||||
// TODO: (PH) Could implement RSD for non-blog content much more easily now the routing can be applied to any content item... (maybe need a RemotePublishingPart?)
|
|
||||||
// TODO: Must restrict these to appropriate parts/types...
|
|
||||||
describe.For<IContent>("Content")
|
|
||||||
.Match((Func<IContent,bool>)(c => c.Is<BlogPart>()))
|
|
||||||
.Pattern("Rsd", T("Remote Blog Publishing"), T("Remote Blog Publishing destination Url"),
|
|
||||||
(Func<IContent,RouteValueDictionary>)(c => new RouteValueDictionary {
|
|
||||||
{"area", "Orchard.Blogs"},
|
|
||||||
{"controller", "RemoteBlogPublishing"},
|
|
||||||
{"action", "Rsd"},
|
|
||||||
{"blogId", idToken}}))
|
|
||||||
.Pattern("Archive", T("Blog Archives"), T("Displays a list of all blog archives"),
|
|
||||||
(Func<IContent,RouteValueDictionary>)(c => new RouteValueDictionary {
|
|
||||||
{"area", "Orchard.Blogs"},
|
|
||||||
{"controller", "BlogPost"},
|
|
||||||
{"action", "ListByArchive"},
|
|
||||||
{"blogId", idToken},
|
|
||||||
{"archiveData", ""}
|
|
||||||
}))
|
|
||||||
;
|
|
||||||
describe.For<IContent>("Content")
|
|
||||||
.Match((Func<IContent,bool>)(c => c.Is<BlogPostPart>()))
|
|
||||||
.Pattern("Archive.Year", T("Blog Archives by Year"), T("Displays a list of all blog archives for a particular year"),
|
|
||||||
(Func<IContent,RouteValueDictionary>)(c=> new RouteValueDictionary {
|
|
||||||
{"area", "Orchard.Blogs"},
|
|
||||||
{"controller", "BlogPost"},
|
|
||||||
{"action", "ListByArchive"},
|
|
||||||
{"blogId", idParentToken},
|
|
||||||
{"archiveData", String.Format("{0}",yearToken)}
|
|
||||||
}))
|
|
||||||
.Pattern("Archive.Month", T("Blog Archives by Month"), T("Displays a list of all blog archives for a particular year and month"),
|
|
||||||
(Func<IContent,RouteValueDictionary>)(c => new RouteValueDictionary {
|
|
||||||
{"area", "Orchard.Blogs"},
|
|
||||||
{"controller", "BlogPost"},
|
|
||||||
{"action", "ListByArchive"},
|
|
||||||
{"blogId", idParentToken},
|
|
||||||
{"archiveData", String.Format("{0}/{1}",yearToken,monthToken)}
|
|
||||||
}))
|
|
||||||
.Pattern("Archive.Day", T("Blog Archives by Day"), T("Displays a list of all blog archives for a particular date"),
|
|
||||||
(Func<IContent,RouteValueDictionary>)(c => new RouteValueDictionary {
|
|
||||||
{"area", "Orchard.Blogs"},
|
|
||||||
{"controller", "BlogPost"},
|
|
||||||
{"action", "ListByArchive"},
|
|
||||||
{"blogId", idParentToken},
|
|
||||||
{"archiveData", String.Format("{0}/{1}/{2}",yearToken,monthToken,dayToken)}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Suggest(dynamic suggest) {
|
|
||||||
suggest.For("Content")
|
|
||||||
.Suggest("Rsd", "blog-title/rsd", blogToken + "/rsd", T("Rsd is a sub-path of the blog post"))
|
|
||||||
.Suggest("Archives", "blog-title/archives", blogToken + "/archives", T("Archives is a sub-path of the blog post"))
|
|
||||||
.Suggest("View", "blog-title", blogToken, T("Blog title"))
|
|
||||||
.Suggest("View", "blog-title/post-title", blogPostToken, T("Nested blog/post path"))
|
|
||||||
.Suggest("Archive.Year", "blog-title/post-title/archives/yy", String.Format("{0}/archives/{1}",blogPostToken,yearToken), T("Archives year"))
|
|
||||||
.Suggest("Archive.Month", "blog-title/post-title/archives/yy/mm", String.Format("{0}/archives/{1}/{2}",blogPostToken,yearToken,monthToken), T("Archives year/month"))
|
|
||||||
.Suggest("Archive.Day", "blog-title/post-title/archives/yy/mm/dd", String.Format("{0}/archives/{1}/{2}/{3}", blogPostToken, yearToken,monthToken,dayToken), T("Archives year/month/day"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.Mvc.Routes;
|
using Orchard.Mvc.Routes;
|
||||||
|
|
||||||
namespace Orchard.Blogs {
|
namespace Orchard.Blogs {
|
||||||
public class Routes : IRouteProvider {
|
public class Routes : IRouteProvider {
|
||||||
public Routes() {
|
private readonly IArchiveConstraint _archiveConstraint;
|
||||||
|
private readonly IRsdConstraint _rsdConstraint;
|
||||||
|
|
||||||
|
public Routes(
|
||||||
|
IArchiveConstraint archiveConstraint,
|
||||||
|
IRsdConstraint rsdConstraint) {
|
||||||
|
_archiveConstraint = archiveConstraint;
|
||||||
|
_rsdConstraint = rsdConstraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
public void GetRoutes(ICollection<RouteDescriptor> routes) {
|
||||||
@@ -168,6 +176,39 @@ namespace Orchard.Blogs {
|
|||||||
{"area", "Orchard.Blogs"}
|
{"area", "Orchard.Blogs"}
|
||||||
},
|
},
|
||||||
new MvcRouteHandler())
|
new MvcRouteHandler())
|
||||||
|
},
|
||||||
|
new RouteDescriptor {
|
||||||
|
Route = new Route(
|
||||||
|
"{*path}",
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Orchard.Blogs"},
|
||||||
|
{"controller", "BlogPost"},
|
||||||
|
{"action", "ListByArchive"}
|
||||||
|
},
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"path", _archiveConstraint},
|
||||||
|
},
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Orchard.Blogs"}
|
||||||
|
},
|
||||||
|
new MvcRouteHandler())
|
||||||
|
},
|
||||||
|
new RouteDescriptor {
|
||||||
|
Priority = 11,
|
||||||
|
Route = new Route(
|
||||||
|
"{*path}",
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Orchard.Blogs"},
|
||||||
|
{"controller", "RemoteBlogPublishing"},
|
||||||
|
{"action", "Rsd"}
|
||||||
|
},
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"path", _rsdConstraint}
|
||||||
|
},
|
||||||
|
new RouteValueDictionary {
|
||||||
|
{"area", "Orchard.Blogs"}
|
||||||
|
},
|
||||||
|
new MvcRouteHandler())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Routing;
|
||||||
|
using Orchard.Blogs.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Blogs.Routing {
|
||||||
|
public class ArchiveConstraint : IArchiveConstraint {
|
||||||
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
|
|
||||||
|
public ArchiveConstraint(IBlogPathConstraint blogPathConstraint) {
|
||||||
|
_blogPathConstraint = blogPathConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
var path = FindPath(parameterValue);
|
||||||
|
if (path == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var archiveData = FindArchiveData(parameterValue);
|
||||||
|
if (archiveData == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _blogPathConstraint.FindPath(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FindPath(string path) {
|
||||||
|
var archiveIndex = path.IndexOf("/archive/", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (archiveIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Substring(0, archiveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArchiveData FindArchiveData(string path) {
|
||||||
|
var archiveIndex = path.IndexOf("/archive/", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (archiveIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new ArchiveData(path.Substring(archiveIndex + "/archive/".Length));
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
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 BlogPathConstraint : IBlogPathConstraint {
|
||||||
|
private readonly ConcurrentDictionary<string, string> _paths = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public BlogPathConstraint() {
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
public void SetPaths(IEnumerable<string> paths) {
|
||||||
|
_paths.Clear();
|
||||||
|
foreach(var path in paths) {
|
||||||
|
AddPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug("Blog paths: {0}", string.Join(", ", paths.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FindPath(string path) {
|
||||||
|
string actual;
|
||||||
|
// path can be null for homepage
|
||||||
|
path = path ?? String.Empty;
|
||||||
|
|
||||||
|
return _paths.TryGetValue(path, out actual) ? actual : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPath(string path) {
|
||||||
|
// path can be null for homepage
|
||||||
|
path = path ?? String.Empty;
|
||||||
|
|
||||||
|
_paths[path] = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePath(string path) {
|
||||||
|
// path can be null for homepage
|
||||||
|
path = path ?? String.Empty;
|
||||||
|
|
||||||
|
_paths.TryRemove(path, out path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
|
||||||
|
if (routeDirection == RouteDirection.UrlGeneration)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
object value;
|
||||||
|
if (values.TryGetValue(parameterName, out value)) {
|
||||||
|
var parameterValue = Convert.ToString(value);
|
||||||
|
|
||||||
|
return _paths.ContainsKey(parameterValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Orchard.Blogs.Services;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.Aspects;
|
||||||
|
using Orchard.Environment;
|
||||||
|
using Orchard.Tasks;
|
||||||
|
|
||||||
|
namespace Orchard.Blogs.Routing {
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class BlogPathConstraintUpdator : IOrchardShellEvents, IBackgroundTask {
|
||||||
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
|
private readonly IBlogService _blogService;
|
||||||
|
|
||||||
|
public BlogPathConstraintUpdator(IBlogPathConstraint blogPathConstraint, IBlogService blogService) {
|
||||||
|
_blogPathConstraint = blogPathConstraint;
|
||||||
|
_blogService = blogService;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOrchardShellEvents.Activated() {
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOrchardShellEvents.Terminating() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void IBackgroundTask.Sweep() {
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Refresh() {
|
||||||
|
_blogPathConstraint.SetPaths(_blogService.Get().Select(b => b.As<IAliasAspect>().Path).ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Web.Routing;
|
||||||
|
using Orchard.Blogs.Models;
|
||||||
|
|
||||||
|
namespace Orchard.Blogs.Routing {
|
||||||
|
public interface IArchiveConstraint : IRouteConstraint, ISingletonDependency {
|
||||||
|
string FindPath(string path);
|
||||||
|
ArchiveData FindArchiveData(string path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using System.Web.Routing;
|
||||||
|
|
||||||
|
namespace Orchard.Blogs.Routing {
|
||||||
|
public interface IRsdConstraint : IRouteConstraint, ISingletonDependency {
|
||||||
|
string FindPath(string path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Routing;
|
||||||
|
|
||||||
|
namespace Orchard.Blogs.Routing {
|
||||||
|
public class RsdConstraint : IRsdConstraint {
|
||||||
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
|
|
||||||
|
public RsdConstraint(IBlogPathConstraint blogPathConstraint) {
|
||||||
|
_blogPathConstraint = blogPathConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
|
||||||
|
if (routeDirection == RouteDirection.UrlGeneration)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
object value;
|
||||||
|
if (values.TryGetValue(parameterName, out value)) {
|
||||||
|
var parameterValue = Convert.ToString(value);
|
||||||
|
|
||||||
|
var path = FindPath(parameterValue);
|
||||||
|
if(path == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _blogPathConstraint.FindPath(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FindPath(string path) {
|
||||||
|
if (!path.EndsWith("/rsd", StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Substring(0, path.Length - "/rsd".Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Orchard.Blogs.Models;
|
using Orchard.Blogs.Models;
|
||||||
|
using Orchard.Blogs.Routing;
|
||||||
using Orchard.ContentManagement;
|
using Orchard.ContentManagement;
|
||||||
using Orchard.ContentManagement.Aspects;
|
using Orchard.ContentManagement.Aspects;
|
||||||
using Orchard.Core.Title.Models;
|
using Orchard.Core.Title.Models;
|
||||||
@@ -10,12 +11,15 @@ namespace Orchard.Blogs.Services {
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class BlogService : IBlogService {
|
public class BlogService : IBlogService {
|
||||||
private readonly IContentManager _contentManager;
|
private readonly IContentManager _contentManager;
|
||||||
|
private readonly IBlogPathConstraint _blogPathConstraint;
|
||||||
|
|
||||||
public BlogService(IContentManager contentManager) {
|
public BlogService(IContentManager contentManager, IBlogPathConstraint blogPathConstraint) {
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
|
_blogPathConstraint = blogPathConstraint;
|
||||||
}
|
}
|
||||||
public BlogPart Get(int id) {
|
|
||||||
return _contentManager.Get<BlogPart>(id);
|
public BlogPart Get(string path) {
|
||||||
|
return _contentManager.Query<BlogPart>().List().FirstOrDefault(rr => rr.As<IAliasAspect>().Path == path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContentItem Get(int id, VersionOptions versionOptions) {
|
public ContentItem Get(int id, VersionOptions versionOptions) {
|
||||||
@@ -35,6 +39,7 @@ namespace Orchard.Blogs.Services {
|
|||||||
|
|
||||||
public void Delete(ContentItem blog) {
|
public void Delete(ContentItem blog) {
|
||||||
_contentManager.Remove(blog);
|
_contentManager.Remove(blog);
|
||||||
|
_blogPathConstraint.RemovePath(blog.As<IAliasAspect>().Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using Orchard.ContentManagement;
|
|||||||
|
|
||||||
namespace Orchard.Blogs.Services {
|
namespace Orchard.Blogs.Services {
|
||||||
public interface IBlogService : IDependency {
|
public interface IBlogService : IDependency {
|
||||||
BlogPart Get(int id);
|
BlogPart Get(string path);
|
||||||
ContentItem Get(int id, VersionOptions versionOptions);
|
ContentItem Get(int id, VersionOptions versionOptions);
|
||||||
IEnumerable<BlogPart> Get();
|
IEnumerable<BlogPart> Get();
|
||||||
IEnumerable<BlogPart> Get(VersionOptions versionOptions);
|
IEnumerable<BlogPart> Get(VersionOptions versionOptions);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Orchard.Blogs.Models;
|
|||||||
|
|
||||||
namespace Orchard.Blogs.ViewModels {
|
namespace Orchard.Blogs.ViewModels {
|
||||||
public class BlogArchivesViewModel {
|
public class BlogArchivesViewModel {
|
||||||
|
public string Slug { get; set; }
|
||||||
public IEnumerable<BlogPart> Blogs { get; set; }
|
public IEnumerable<BlogPart> Blogs { get; set; }
|
||||||
public int BlogId { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using Orchard.Blogs.Models;
|
|||||||
namespace Orchard.Blogs.ViewModels {
|
namespace Orchard.Blogs.ViewModels {
|
||||||
public class RecentBlogPostsViewModel {
|
public class RecentBlogPostsViewModel {
|
||||||
public int Count { get; set; }
|
public int Count { get; set; }
|
||||||
public int BlogId { get; set; }
|
public string Slug { get; set; }
|
||||||
public IEnumerable<BlogPart> Blogs { get; set; }
|
public IEnumerable<BlogPart> Blogs { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -1,6 +1,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
@@ -32,3 +33,4 @@ using System.Runtime.InteropServices;
|
|||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
|
[assembly: SecurityTransparent]
|
||||||
|
|||||||
@@ -61,8 +61,6 @@
|
|||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Projections\TagsFilterForms.cs" />
|
<Compile Include="Projections\TagsFilterForms.cs" />
|
||||||
<Compile Include="Providers\TagPatterns.cs" />
|
|
||||||
<Compile Include="Providers\TagTokens.cs" />
|
|
||||||
<Compile Include="ResourceManifest.cs" />
|
<Compile Include="ResourceManifest.cs" />
|
||||||
<Compile Include="Services\ITagService.cs" />
|
<Compile Include="Services\ITagService.cs" />
|
||||||
<Compile Include="Services\XmlRpcHandler.cs" />
|
<Compile Include="Services\XmlRpcHandler.cs" />
|
||||||
@@ -106,10 +104,6 @@
|
|||||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||||
<Name>Orchard.Core</Name>
|
<Name>Orchard.Core</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\Orchard.Tokens\Orchard.Tokens.csproj">
|
|
||||||
<Project>{6F759635-13D7-4E94-BCC9-80445D63F117}</Project>
|
|
||||||
<Name>Orchard.Tokens</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Placement.info">
|
<Content Include="Placement.info">
|
||||||
|
|||||||
@@ -32,3 +32,4 @@ using System.Security;
|
|||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
[assembly: AssemblyVersion("1.3.0")]
|
[assembly: AssemblyVersion("1.3.0")]
|
||||||
[assembly: AssemblyFileVersion("1.3.0")]
|
[assembly: AssemblyFileVersion("1.3.0")]
|
||||||
|
[assembly: SecurityTransparent]
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Orchard.Tags.Services;
|
|
||||||
using Orchard.Localization;
|
|
||||||
using Orchard.Tags.Models;
|
|
||||||
using System.Web.Routing;
|
|
||||||
using Orchard.Events;
|
|
||||||
|
|
||||||
namespace Orchard.Tags.Providers {
|
|
||||||
|
|
||||||
public interface IRoutePatternProvider : IEventHandler {
|
|
||||||
void Describe(dynamic describe);
|
|
||||||
void Suggest(dynamic suggest);
|
|
||||||
}
|
|
||||||
public class TagPatterns : IRoutePatternProvider {
|
|
||||||
|
|
||||||
private readonly ITagService _tagService;
|
|
||||||
|
|
||||||
public TagPatterns(
|
|
||||||
ITagService tagService
|
|
||||||
) {
|
|
||||||
_tagService = tagService;
|
|
||||||
T = NullLocalizer.Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Localizer T { get; set; }
|
|
||||||
|
|
||||||
public void Describe(dynamic describe) {
|
|
||||||
describe.For<TagRecord>("Tags", T("Tags"), T("Tags url patterns"), (Func<TagRecord, string>)GetId, (Func<string, TagRecord>)GetTag, (Func<TagRecord, IDictionary<string, object>>)GetContext)
|
|
||||||
.Pattern("Tags", T("View all tags"), T("A list of all tags are displayed on this page"), (Func<TagRecord, RouteValueDictionary>)GetTagsRouteValues)
|
|
||||||
.Pattern("View", T("View tagged content"), T("Tagged content will be listed on this Url for each tag"), (Func<TagRecord, RouteValueDictionary>)GetRouteValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RouteValueDictionary GetRouteValues(TagRecord tag) {
|
|
||||||
return new RouteValueDictionary(new{
|
|
||||||
area = "Orchard.Tags",
|
|
||||||
controller = "Home",
|
|
||||||
action = "Search",
|
|
||||||
tagName = tag.TagName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public RouteValueDictionary GetTagsRouteValues(TagRecord tag) {
|
|
||||||
return new RouteValueDictionary(new {
|
|
||||||
area = "Orchard.Tags",
|
|
||||||
controller = "Home",
|
|
||||||
action = "Index"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary<string,object> GetContext(TagRecord tag) {
|
|
||||||
return new Dictionary<string, object> { { "Tag", tag } };
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetId(TagRecord tag) {
|
|
||||||
return tag.Id.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TagRecord GetTag(string id) {
|
|
||||||
return _tagService.GetTag(Convert.ToInt32(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Suggest(dynamic suggest) {
|
|
||||||
suggest.For("Tags")
|
|
||||||
.Suggest("View", "tags/tag-name", "{Tag.Name.Slug}", T("Slugified tag name"))
|
|
||||||
.Suggest("Tags", "tags", "tags", T("Plain /tags url"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Orchard.Tokens;
|
|
||||||
using Orchard.Localization;
|
|
||||||
using Orchard.Tags.Models;
|
|
||||||
|
|
||||||
namespace Orchard.Tags.Providers {
|
|
||||||
public class TagTokens : ITokenProvider {
|
|
||||||
|
|
||||||
public TagTokens() {
|
|
||||||
|
|
||||||
T = NullLocalizer.Instance;
|
|
||||||
|
|
||||||
}
|
|
||||||
public Localizer T { get; set; }
|
|
||||||
public void Describe(DescribeContext context) {
|
|
||||||
|
|
||||||
context.For("Tag", T("Tags"), T("Tag records"))
|
|
||||||
.Token("Name", T("Tag name"), T("Tag name"), "Text");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Evaluate(EvaluateContext context) {
|
|
||||||
context.For<TagRecord>("Tag")
|
|
||||||
.Token("", t => t.TagName)
|
|
||||||
.Token("Name", t => t.TagName)
|
|
||||||
// By chaining the name to text it can be slugified in Autoroute
|
|
||||||
.Chain("Name", "Text", t => t.TagName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
@@ -35,3 +36,4 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
[assembly: AssemblyVersion("1.3.0")]
|
[assembly: AssemblyVersion("1.3.0")]
|
||||||
[assembly: AssemblyFileVersion("1.3.0")]
|
[assembly: AssemblyFileVersion("1.3.0")]
|
||||||
|
[assembly: SecurityTransparent]
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Orchard.ContentManagement.Aspects {
|
||||||
|
public interface IAliasAspect : IContent {
|
||||||
|
string Path { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace Orchard.ContentManagement.Aspects {
|
namespace Orchard.ContentManagement.Aspects {
|
||||||
public interface IRoutableAspect : ITitleAspect {
|
public interface IRoutableAspect : ITitleAspect, IAliasAspect {
|
||||||
string Slug { get; set; }
|
string Slug { get; set; }
|
||||||
string Path { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,6 +159,7 @@
|
|||||||
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
||||||
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
||||||
<Compile Include="Caching\IParallelCacheContext.cs" />
|
<Compile Include="Caching\IParallelCacheContext.cs" />
|
||||||
|
<Compile Include="ContentManagement\Aspects\IAliasAspect.cs" />
|
||||||
<Compile Include="ContentManagement\Aspects\ITitleAspect.cs" />
|
<Compile Include="ContentManagement\Aspects\ITitleAspect.cs" />
|
||||||
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />
|
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />
|
||||||
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user