diff --git a/src/Orchard.Specs/Blogs.feature b/src/Orchard.Specs/Blogs.feature
index 9dad395d7..550056c30 100644
--- a/src/Orchard.Specs/Blogs.feature
+++ b/src/Orchard.Specs/Blogs.feature
@@ -147,4 +147,26 @@ Scenario: The virtual path of my installation when at the root is reflected in t
| Routable.Title | My Blog |
And I hit "Save"
And I go to "admin/blogs/my-blog/posts/create"
- Then I should see "http\://localhost/my-blog/"
\ No newline at end of file
+ Then I should see "http\://localhost/my-blog/"
+
+Scenario: I set my blog to be the content for the home page and the posts for the blog should still be at the blog path prefixed path
+ Given I have installed Orchard
+ When I go to "admin/blogs/create"
+ And I fill in
+ | name | value |
+ | Routable.Title | My Blog |
+ | Routable.PromoteToHomePage | true |
+ And I hit "Save"
+ And I go to "admin/blogs/my-blog/posts/create"
+ And I fill in
+ | name | value |
+ | Routable.Title | My Post |
+ | Body.Text | Hi there. |
+ And I hit "Publish Now"
+ And I am redirected
+ And I go to "/Default.aspx"
+ Then I should see "
My Blog
"
+ When I go to "/my-blog"
+ Then the status should be 404 "Not Found"
+ When I go to "/my-blog/my-post"
+ Then I should see "My Post
"
diff --git a/src/Orchard.Specs/Blogs.feature.cs b/src/Orchard.Specs/Blogs.feature.cs
index b00e46221..4e88c4f33 100644
--- a/src/Orchard.Specs/Blogs.feature.cs
+++ b/src/Orchard.Specs/Blogs.feature.cs
@@ -457,6 +457,67 @@ this.ScenarioSetup(scenarioInfo);
testRunner.And("I go to \"admin/blogs/my-blog/posts/create\"");
#line 150
testRunner.Then("I should see \"http\\://localhost/my-blog/\"");
+#line hidden
+ testRunner.CollectScenarioErrors();
+ }
+
+ [NUnit.Framework.TestAttribute()]
+ [NUnit.Framework.DescriptionAttribute("I set my blog to be the content for the home page and the posts for the blog shou" +
+ "ld still be at the blog path prefixed path")]
+ public virtual void ISetMyBlogToBeTheContentForTheHomePageAndThePostsForTheBlogShouldStillBeAtTheBlogPathPrefixedPath()
+ {
+ TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I set my blog to be the content for the home page and the posts for the blog shou" +
+ "ld still be at the blog path prefixed path", ((string[])(null)));
+#line 152
+this.ScenarioSetup(scenarioInfo);
+#line 153
+ testRunner.Given("I have installed Orchard");
+#line 154
+ testRunner.When("I go to \"admin/blogs/create\"");
+#line hidden
+ TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] {
+ "name",
+ "value"});
+ table15.AddRow(new string[] {
+ "Routable.Title",
+ "My Blog"});
+ table15.AddRow(new string[] {
+ "Routable.PromoteToHomePage",
+ "true"});
+#line 155
+ testRunner.And("I fill in", ((string)(null)), table15);
+#line 159
+ testRunner.And("I hit \"Save\"");
+#line 160
+ testRunner.And("I go to \"admin/blogs/my-blog/posts/create\"");
+#line hidden
+ TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] {
+ "name",
+ "value"});
+ table16.AddRow(new string[] {
+ "Routable.Title",
+ "My Post"});
+ table16.AddRow(new string[] {
+ "Body.Text",
+ "Hi there."});
+#line 161
+ testRunner.And("I fill in", ((string)(null)), table16);
+#line 165
+ testRunner.And("I hit \"Publish Now\"");
+#line 166
+ testRunner.And("I am redirected");
+#line 167
+ testRunner.And("I go to \"/Default.aspx\"");
+#line 168
+ testRunner.Then("I should see \"My Blog
\"");
+#line 169
+ testRunner.When("I go to \"/my-blog\"");
+#line 170
+ testRunner.Then("the status should be 404 \"Not Found\"");
+#line 171
+ testRunner.When("I go to \"/my-blog/my-post\"");
+#line 172
+ testRunner.Then("I should see \"My Post
\"");
#line hidden
testRunner.CollectScenarioErrors();
}
diff --git a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs
index 93957e3a9..fa7418b6c 100644
--- a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs
+++ b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
@@ -8,6 +9,7 @@ using Orchard.Core.Routable.Services;
using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.Localization;
+using Orchard.Services;
using Orchard.Themes;
namespace Orchard.Core.Routable.Controllers {
@@ -16,25 +18,33 @@ namespace Orchard.Core.Routable.Controllers {
private readonly IContentManager _contentManager;
private readonly ITransactionManager _transactionManager;
private readonly IRoutablePathConstraint _routablePathConstraint;
+ private readonly IWorkContextAccessor _workContextAccessor;
+ private readonly IHomePageProvider _routableHomePageProvider;
public ItemController(
IContentManager contentManager,
ITransactionManager transactionManager,
- IRoutablePathConstraint routablePathConstraint,
- IShapeFactory shapeFactory) {
+ IRoutablePathConstraint routablePathConstraint,
+ IShapeFactory shapeFactory,
+ IWorkContextAccessor workContextAccessor,
+ IEnumerable homePageProviders) {
_contentManager = contentManager;
_transactionManager = transactionManager;
_routablePathConstraint = routablePathConstraint;
+ _workContextAccessor = workContextAccessor;
+ _routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
Shape = shapeFactory;
+ T = NullLocalizer.Instance;
}
+ public Localizer T { get; set; }
dynamic Shape { get; set; }
[Themed]
public ActionResult Display(string path) {
var matchedPath = _routablePathConstraint.FindPath(path);
- if (string.IsNullOrEmpty(matchedPath)) {
- throw new ApplicationException("404 - should not have passed path constraint");
+ if (matchedPath == null) {
+ throw new ApplicationException(T("404 - should not have passed path constraint").Text);
}
var hits = _contentManager
@@ -42,13 +52,20 @@ namespace Orchard.Core.Routable.Controllers {
.Where(r => r.Path == matchedPath)
.Slice(0, 2);
if (hits.Count() == 0) {
- throw new ApplicationException("404 - should not have passed path constraint");
+ throw new ApplicationException(T("404 - should not have passed path constraint").Text);
}
if (hits.Count() != 1) {
- throw new ApplicationException("Ambiguous content");
+ throw new ApplicationException(T("Ambiguous content").Text);
}
- dynamic model = _contentManager.BuildDisplay(hits.Single());
+ var item = hits.Single();
+ // primary action run for a home paged item shall not pass
+ if (!RouteData.DataTokens.ContainsKey("ParentActionViewContext")
+ && item.Id == _routableHomePageProvider.GetHomePageId(_workContextAccessor.GetContext().CurrentSite.HomePage)) {
+ return HttpNotFound();
+ }
+
+ dynamic model = _contentManager.BuildDisplay(item);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);
}
diff --git a/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs b/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs
index 62682ab66..5ba7b9384 100644
--- a/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs
+++ b/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs
@@ -23,6 +23,7 @@ namespace Orchard.Core.Routable.Handlers {
IRepository repository,
IRoutablePathConstraint routablePathConstraint,
IRoutableService routableService,
+ IWorkContextAccessor workContextAccessor,
IEnumerable homePageProviders) {
_services = services;
_routablePathConstraint = routablePathConstraint;
@@ -46,8 +47,10 @@ namespace Orchard.Core.Routable.Handlers {
OnPublished((context, route) => {
FinalizePath(route, context, processSlug);
- if (route.ContentItem.Id != 0 && route.PromoteToHomePage && _routableHomePageProvider != null)
+ if (route.ContentItem.Id != 0 && route.PromoteToHomePage && _routableHomePageProvider != null) {
_services.WorkContext.CurrentSite.HomePage = _routableHomePageProvider.GetSettingValue(route.ContentItem.Id);
+ _routablePathConstraint.AddPath("");
+ }
});
OnRemoved((context, route) => {
@@ -87,6 +90,14 @@ namespace Orchard.Core.Routable.Handlers {
}
public class RoutePartHandlerBase : ContentHandlerBase {
+ private readonly IWorkContextAccessor _workContextAccessor;
+ private readonly IHomePageProvider _routableHomePageProvider;
+
+ public RoutePartHandlerBase(IWorkContextAccessor workContextAccessor, IEnumerable homePageProviders) {
+ _workContextAccessor = workContextAccessor;
+ _routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
+ }
+
public override void GetContentItemMetadata(GetContentItemMetadataContext context) {
var routable = context.ContentItem.As();
@@ -98,11 +109,15 @@ namespace Orchard.Core.Routable.Handlers {
// set the display route values if it hasn't been set or only has been set by the Contents module.
// allows other modules to set their own display. probably not common enough to warrant some priority implemntation
if (context.Metadata.DisplayRouteValues == null || context.Metadata.DisplayRouteValues["Area"] as string == "Contents") {
+ var itemPath = routable.Id == _routableHomePageProvider.GetHomePageId(_workContextAccessor.GetContext().CurrentSite.HomePage)
+ ? ""
+ : routable.Path;
+
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
{"Area", "Routable"},
{"Controller", "Item"},
{"Action", "Display"},
- {"path", routable.Path}
+ {"path", itemPath}
};
}
}
diff --git a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs
index 47c80c74f..24a00b28a 100644
--- a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs
+++ b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs
@@ -1,7 +1,9 @@
-using System.Web.Mvc;
+using System;
+using System.Web.Mvc;
using JetBrains.Annotations;
using Orchard.Core.Routable.Models;
using Orchard.DisplayManagement;
+using Orchard.Localization;
using Orchard.Services;
using Orchard.ContentManagement;
@@ -16,8 +18,10 @@ namespace Orchard.Core.Routable.Services {
IShapeFactory shapeFactory) {
_contentManager = contentManager;
Shape = shapeFactory;
+ T = NullLocalizer.Instance;
}
+ public Localizer T { get; set; }
dynamic Shape { get; set; }
public string GetProviderName() {
@@ -28,6 +32,15 @@ namespace Orchard.Core.Routable.Services {
return GetProviderName() + ";" + id;
}
+ public int GetHomePageId(string value) {
+ int id;
+
+ if (string.IsNullOrWhiteSpace(value) || !int.TryParse(value.Substring(Name.Length + 1), out id))
+ throw new ApplicationException(T("Invalid home page setting value for {0}: {1}", Name, value).Text);
+
+ return id;
+ }
+
public ActionResult GetHomePage(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
if (contentItem == null || !contentItem.Is())
diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs
index 790a10383..5661a51ce 100644
--- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs
+++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs
@@ -1,11 +1,14 @@
+using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.Blogs.Extensions;
using Orchard.Blogs.Routing;
using Orchard.Blogs.Services;
using Orchard.Core.Feeds;
+using Orchard.Core.Routable.Services;
using Orchard.DisplayManagement;
using Orchard.Logging;
+using Orchard.Services;
using Orchard.Themes;
using Orchard.UI.Navigation;
@@ -17,6 +20,8 @@ namespace Orchard.Blogs.Controllers {
private readonly IBlogPostService _blogPostService;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IFeedManager _feedManager;
+ private readonly IWorkContextAccessor _workContextAccessor;
+ private readonly IHomePageProvider _routableHomePageProvider;
public BlogController(
IOrchardServices services,
@@ -24,12 +29,16 @@ namespace Orchard.Blogs.Controllers {
IBlogPostService blogPostService,
IBlogSlugConstraint blogSlugConstraint,
IFeedManager feedManager,
- IShapeFactory shapeFactory) {
+ IShapeFactory shapeFactory,
+ IWorkContextAccessor workContextAccessor,
+ IEnumerable homePageProviders) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_blogSlugConstraint = blogSlugConstraint;
_feedManager = feedManager;
+ _workContextAccessor = workContextAccessor;
+ _routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
Logger = NullLogger.Instance;
Shape = shapeFactory;
}
@@ -59,6 +68,12 @@ namespace Orchard.Blogs.Controllers {
if (blogPart == null)
return HttpNotFound();
+ // primary action run for a home paged item shall not pass
+ if (!RouteData.DataTokens.ContainsKey("ParentActionViewContext")
+ && blogPart.Id == _routableHomePageProvider.GetHomePageId(_workContextAccessor.GetContext().CurrentSite.HomePage)) {
+ return HttpNotFound();
+ }
+
_feedManager.Register(blogPart);
var blogPosts = _blogPostService.Get(blogPart, pager.GetStartIndex(), pager.PageSize)
.Select(b => _services.ContentManager.BuildDisplay(b, "Summary"));
diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs
index afbb78849..70ed19a5e 100644
--- a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs
+++ b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs
@@ -1,17 +1,39 @@
+using System.Collections.Generic;
+using System.Linq;
using System.Web.Routing;
using JetBrains.Annotations;
using Orchard.Blogs.Models;
+using Orchard.Blogs.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Routable.Models;
+using Orchard.Core.Routable.Services;
using Orchard.Data;
+using Orchard.Services;
namespace Orchard.Blogs.Handlers {
[UsedImplicitly]
public class BlogPartHandler : ContentHandler {
- public BlogPartHandler(IRepository repository) {
+ private readonly IWorkContextAccessor _workContextAccessor;
+ private readonly IBlogSlugConstraint _blogSlugConstraint;
+ private readonly IHomePageProvider _routableHomePageProvider;
+
+ public BlogPartHandler(IRepository repository, IWorkContextAccessor workContextAccessor, IEnumerable homePageProviders, IBlogSlugConstraint blogSlugConstraint) {
+ _workContextAccessor = workContextAccessor;
+ _blogSlugConstraint = blogSlugConstraint;
+ _routableHomePageProvider = homePageProviders.SingleOrDefault(p => p.GetProviderName() == RoutableHomePageProvider.Name);
Filters.Add(StorageFilter.For(repository));
+ OnPublished((context, route) => {
+ if (route.Is()) {
+ if (route.ContentItem.Id != 0 && route.PromoteToHomePage)
+ _blogSlugConstraint.AddSlug("");
+ }
+ else if (route.ContentItem.Id != 0 && route.PromoteToHomePage) {
+ _blogSlugConstraint.RemoveSlug("");
+ }
+ });
+
OnGetDisplayShape((context, blog) => {
context.Shape.Description = blog.Description;
context.Shape.PostCount = blog.PostCount;
@@ -24,11 +46,15 @@ namespace Orchard.Blogs.Handlers {
if (blog == null)
return;
+ var blogSlug = blog.Id == _routableHomePageProvider.GetHomePageId(_workContextAccessor.GetContext().CurrentSite.HomePage)
+ ? ""
+ : blog.As().Slug;
+
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "Blog"},
{"Action", "Item"},
- {"blogSlug", blog.As().Slug}
+ {"blogSlug", blogSlug}
};
context.Metadata.CreateRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs
index e6407fdcc..73759e2ff 100644
--- a/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs
+++ b/src/Orchard.Web/Modules/Orchard.Blogs/Routes.cs
@@ -243,7 +243,8 @@ namespace Orchard.Blogs {
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "Blog"},
- {"action", "Item"}
+ {"action", "Item"},
+ {"blogSlug", ""}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint}
diff --git a/src/Orchard/Services/IHomePageProvider.cs b/src/Orchard/Services/IHomePageProvider.cs
index 7def1fd96..be2d9a06c 100644
--- a/src/Orchard/Services/IHomePageProvider.cs
+++ b/src/Orchard/Services/IHomePageProvider.cs
@@ -4,6 +4,7 @@ namespace Orchard.Services {
public interface IHomePageProvider : IDependency {
string GetProviderName();
string GetSettingValue(int itemId);
+ int GetHomePageId(string value);
ActionResult GetHomePage(int itemId);
}
}