Handling Rsd and Archives

--HG--
branch : autoroute
This commit is contained in:
Sebastien Ros
2012-01-31 14:24:46 -08:00
parent 7a23c5dab4
commit 49cdb191fd
30 changed files with 284 additions and 189 deletions
+6 -6
View File
@@ -1,9 +1,9 @@
d91108343ff1259cd3e35b2c080eb166d024711b src/Orchard.Web/Modules/Orchard.Alias 81cb672c85fd980dd3db0515544b79a918e5eb69 src/Orchard.Web/Modules/Orchard.Alias
0b87c2916b43a87addfa534470c3bd7a47be662a src/Orchard.Web/Modules/Orchard.Autoroute a3329c82a2636eb166c46f3cfdadd18eca4e4d7f 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
f2a3984789ebe5caf2822ccb9e1d2c953add9c35 src/Orchard.Web/Modules/Orchard.Rules f2a3984789ebe5caf2822ccb9e1d2c953add9c35 src/Orchard.Web/Modules/Orchard.Rules
ce578373f907c0a55fd91229a344f0755f290174 src/Orchard.Web/Modules/Orchard.TaskLease ce578373f907c0a55fd91229a344f0755f290174 src/Orchard.Web/Modules/Orchard.TaskLease
42d34730d8bb22052585ca94e3e945111aea3b9d src/Orchard.Web/Modules/Orchard.Tokens 2373765b3f1f4171b09b1458f7dce9e8b83db0a2 src/Orchard.Web/Modules/Orchard.Tokens
08eadecb5e5fae52e8b4c7d1c60f29e51c63b2ca src/orchard.web/modules/Orchard.Fields d8a83a676cb3b9d0266ec83ac6a1e8562821d82b 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;
@@ -59,11 +58,14 @@ namespace Orchard.Blogs.Controllers {
return View((object)viewModel); return View((object)viewModel);
} }
public ActionResult Item(int blogId, PagerParameters pagerParameters) { public ActionResult Item(string blogPath, PagerParameters pagerParameters) {
// TODO: (PH:Autoroute) Should use Containers so we can lose this action and rely on ContainerPartDriver instead // 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 correctedPath = _blogPathConstraint.FindPath(blogPath);
if (correctedPath == null)
return HttpNotFound();
var blogPart = _blogService.Get(blogId, VersionOptions.Published).As<BlogPart>(); var blogPart = _blogService.Get(correctedPath);
if (blogPart == null) if (blogPart == null)
return HttpNotFound(); return HttpNotFound();
@@ -36,9 +36,9 @@ 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 blogPath, string archiveData) {
//TODO: (erikpo) Move looking up the current blog up into a modelbinder //TODO: (erikpo) Move looking up the current blog up into a modelbinder
BlogPart blogPart = _blogService.Get(blogId,VersionOptions.Published).As<BlogPart>(); BlogPart blogPart = _blogService.Get(blogPath);
if (blogPart == null) if (blogPart == null)
return HttpNotFound(); return HttpNotFound();
@@ -21,10 +21,10 @@ namespace Orchard.Blogs.Controllers {
protected ILogger Logger { get; set; } protected ILogger Logger { get; set; }
public ActionResult Rsd(int blogId) { public ActionResult Rsd(string blogPath) {
Logger.Debug("RSD requested"); Logger.Debug("RSD requested");
BlogPart blogPart = _blogService.Get(blogId); 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);
} }
} }
} }
@@ -1,9 +1,9 @@
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.Autoroute.Models;
using Orchard.Blogs.Models; 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 +27,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 { blogPath = blogPart.As<IRoutableAspect>().Path, 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 { blogPath = blogPart.As<AutoroutePart>().DisplayAlias, archiveData = 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 { blogPath = blogPart.As<AutoroutePart>().DisplayAlias, 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) { 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 { blogPath = blogPart.As<AutoroutePart>().DisplayAlias, archiveData = 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.Autoroute.Models;
using Orchard.Blogs.Models; using Orchard.Blogs.Models;
using Orchard.Blogs.Routing;
using Orchard.ContentManagement; using Orchard.ContentManagement;
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<AutoroutePart>().DisplayAlias));
OnUnpublished<BlogPart>((context, blog) => _blogPathConstraint.RemovePath(blog.As<AutoroutePart>().DisplayAlias));
} }
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; }
} }
} }
@@ -79,7 +79,10 @@
<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\IBlogPathConstraint.cs" />
<Compile Include="Routing\IsArchiveConstraint.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" />
@@ -134,6 +137,14 @@
<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.Alias\Orchard.Alias.csproj">
<Project>{475B6C45-B27C-438B-8966-908B9D6D1077}</Project>
<Name>Orchard.Alias</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Autoroute\Orchard.Autoroute.csproj">
<Project>{66FCCD76-2761-47E3-8D11-B45D0001DDAA}</Project>
<Name>Orchard.Autoroute</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Placement.info"> <Content Include="Placement.info">
@@ -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,15 @@
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 IBlogPathConstraint _blogPathConstraint;
public Routes(IBlogPathConstraint blogPathConstraint) {
_blogPathConstraint = blogPathConstraint;
} }
public void GetRoutes(ICollection<RouteDescriptor> routes) { public void GetRoutes(ICollection<RouteDescriptor> routes) {
@@ -168,7 +172,58 @@ namespace Orchard.Blogs {
{"area", "Orchard.Blogs"} {"area", "Orchard.Blogs"}
}, },
new MvcRouteHandler()) new MvcRouteHandler())
} },
new RouteDescriptor {
Route = new Route(
"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 {
{"blogPath", _blogPathConstraint},
{"archiveData", new IsArchiveConstraint()}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogPath}/rsd",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "RemoteBlogPublishing"},
{"action", "Rsd"}
},
new RouteValueDictionary {
{"blogPath", _blogPathConstraint}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
}; };
} }
} }
@@ -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 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.Autoroute.Models;
using Orchard.Blogs.Services;
using Orchard.ContentManagement;
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<AutoroutePart>().DisplayAlias).ToList());
}
}
}
@@ -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,23 @@
using System.Web;
using System.Web.Routing;
using Orchard.Blogs.Models;
namespace Orchard.Blogs.Routing {
public class IsArchiveConstraint : IRouteConstraint {
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection) {
if(values[parameterName] == null) {
return false;
}
try {
var archiveData = new ArchiveData(values[parameterName].ToString());
archiveData.ToDateTime();
return true;
}
catch {
return false;
}
}
}
}
@@ -1,7 +1,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Autoroute.Models;
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 +12,17 @@ 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, BlogPartRecord>()
.Join<AutoroutePartRecord>().Where(rr => rr.DisplayAlias == path)
.Slice(0, 1).FirstOrDefault();
} }
public ContentItem Get(int id, VersionOptions versionOptions) { public ContentItem Get(int id, VersionOptions versionOptions) {
@@ -35,6 +42,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<AutoroutePart>().DisplayAlias);
} }
} }
} }
@@ -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; }
} }
@@ -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]
@@ -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,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]
@@ -2,6 +2,7 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
using System.Threading; using System.Threading;
using Orchard.Environment;
using Orchard.Events; using Orchard.Events;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
@@ -11,14 +12,14 @@ using Orchard.UI.Notify;
namespace Orchard.Exceptions { namespace Orchard.Exceptions {
public class DefaultExceptionPolicy : IExceptionPolicy { public class DefaultExceptionPolicy : IExceptionPolicy {
private readonly INotifier _notifier; private readonly INotifier _notifier;
private readonly Lazy<IAuthorizer> _authorizer; private readonly Work<IAuthorizer> _authorizer;
public DefaultExceptionPolicy() { public DefaultExceptionPolicy() {
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
public DefaultExceptionPolicy(INotifier notifier, Lazy<IAuthorizer> authorizer) { public DefaultExceptionPolicy(INotifier notifier, Work<IAuthorizer> authorizer) {
_notifier = notifier; _notifier = notifier;
_authorizer = authorizer; _authorizer = authorizer;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;