- Changing all BlogPost admin actions to use the post's id instead of slug (since only published slugs are guaranteed to be unique in any container)

- Changing the BlogPost publish action to POST only
- Changing how BlogPosts are published on create to get the publishing/published events fired (temp workaround)
- Adding unique slug generation on publish for out of the editor for a unique published slug guarantee

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045793
This commit is contained in:
skewed
2010-01-21 20:17:40 +00:00
parent a592fae1c3
commit fdae78826b
12 changed files with 102 additions and 36 deletions

View File

@@ -39,7 +39,7 @@ namespace Orchard.Blogs.Controllers {
if (!_authorizer.Authorize(Permissions.ManageBlogs, T("Not allowed to create blogs")))
return new HttpUnauthorizedResult();
Blog blog = _services.ContentManager.New<Blog>("blog");
Blog blog = _services.ContentManager.New<Blog>(BlogDriver.ContentType.Name);
if (blog == null)
return new NotFoundResult();
@@ -57,7 +57,7 @@ namespace Orchard.Blogs.Controllers {
if (!_authorizer.Authorize(Permissions.ManageBlogs, T("Couldn't create blog")))
return new HttpUnauthorizedResult();
model.Blog = _services.ContentManager.UpdateEditorModel(_services.ContentManager.New<Blog>("blog"), this);
model.Blog = _services.ContentManager.UpdateEditorModel(_services.ContentManager.New<Blog>(BlogDriver.ContentType.Name), this);
if (!ModelState.IsValid)
return View(model);

View File

@@ -1,6 +1,5 @@
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Blogs.Models;
using Orchard.Blogs.Services;
using Orchard.Blogs.ViewModels;

View File

@@ -41,7 +41,7 @@ namespace Orchard.Blogs.Controllers {
if (blog == null)
return new NotFoundResult();
var blogPost = _services.ContentManager.New<BlogPost>("blogpost");
var blogPost = _services.ContentManager.New<BlogPost>(BlogPostDriver.ContentType.Name);
blogPost.Blog = blog;
var model = new CreateBlogPostViewModel {
@@ -74,19 +74,21 @@ namespace Orchard.Blogs.Controllers {
}
}
model.BlogPost = _services.ContentManager.UpdateEditorModel(_services.ContentManager.New<BlogPost>("blogpost"), this);
model.BlogPost = _services.ContentManager.UpdateEditorModel(_services.ContentManager.New<BlogPost>(BlogPostDriver.ContentType.Name), this);
model.BlogPost.Item.Blog = blog;
if (!publishNow && publishDate != null)
model.BlogPost.Item.Published = publishDate.Value;
if (!ModelState.IsValid) {
_services.TransactionManager.Cancel();
return View(model);
}
//TODO: (erikpo) Evaluate if publish options should be moved into create or out of create to keep it clean
_services.ContentManager.Create(model.BlogPost.Item.ContentItem, publishNow ? VersionOptions.Published : VersionOptions.Draft);
//todo: (heskew) make it so we no longer need to set as draft on create then publish (all to get the publishing & published events fired)
_services.ContentManager.Create(model.BlogPost.Item.ContentItem, VersionOptions.Draft);
if (publishNow)
_services.ContentManager.Publish(model.BlogPost.Item.ContentItem);
//TEMP: (erikpo) ensure information has committed for this record
var session = _sessionLocator.For(typeof(ContentItemRecord));
@@ -95,7 +97,7 @@ namespace Orchard.Blogs.Controllers {
return Redirect(Url.BlogPost(blogSlug, model.BlogPost.Item.As<RoutableAspect>().Slug));
}
public ActionResult Edit(string blogSlug, string postSlug) {
public ActionResult Edit(string blogSlug, int postId) {
if (!_services.Authorizer.Authorize(Permissions.EditBlogPost, T("Couldn't edit blog post")))
return new HttpUnauthorizedResult();
@@ -105,7 +107,7 @@ namespace Orchard.Blogs.Controllers {
if (blog == null)
return new NotFoundResult();
BlogPost post = _blogPostService.Get(blog, postSlug, VersionOptions.Latest);
BlogPost post = _blogPostService.Get(postId, VersionOptions.Latest);
if (post == null)
return new NotFoundResult();
@@ -118,7 +120,7 @@ namespace Orchard.Blogs.Controllers {
}
[HttpPost, ActionName("Edit")]
public ActionResult EditPOST(string blogSlug, string postSlug) {
public ActionResult EditPOST(string blogSlug, int postId) {
if (!_services.Authorizer.Authorize(Permissions.EditBlogPost, T("Couldn't edit blog post")))
return new HttpUnauthorizedResult();
@@ -130,7 +132,7 @@ namespace Orchard.Blogs.Controllers {
if (blog == null)
return new NotFoundResult();
BlogPost post = _blogPostService.Get(blog, postSlug, VersionOptions.Latest);
BlogPost post = _blogPostService.Get(postId, VersionOptions.Latest);
if (post == null)
return new NotFoundResult();
@@ -172,13 +174,13 @@ namespace Orchard.Blogs.Controllers {
_services.Notifier.Information(T("Blog post information updated."));
if (isDraft) {
return Redirect(Url.BlogPostEdit(blog.Slug, post.Slug));
return Redirect(Url.BlogPostEdit(blog.Slug, post.Id));
}
return Redirect(Url.BlogForAdmin(blog.Slug));
}
[HttpPost]
public ActionResult Delete(string blogSlug, string postSlug) {
public ActionResult Delete(string blogSlug, int postId) {
//refactoring: test PublishBlogPost/PublishOthersBlogPost in addition if published
if (!_services.Authorizer.Authorize(Permissions.DeleteBlogPost, T("Couldn't delete blog post")))
return new HttpUnauthorizedResult();
@@ -189,7 +191,7 @@ namespace Orchard.Blogs.Controllers {
if (blog == null)
return new NotFoundResult();
BlogPost post = _blogPostService.Get(blog, postSlug, VersionOptions.Latest);
BlogPost post = _blogPostService.Get(postId, VersionOptions.Latest);
if (post == null)
return new NotFoundResult();
@@ -201,7 +203,8 @@ namespace Orchard.Blogs.Controllers {
return Redirect(Url.BlogForAdmin(blogSlug));
}
public ActionResult Publish(string blogSlug, string postSlug) {
[HttpPost]
public ActionResult Publish(string blogSlug, int postId) {
if (!_services.Authorizer.Authorize(Permissions.PublishBlogPost, T("Couldn't publish blog post")))
return new HttpUnauthorizedResult();
@@ -211,7 +214,7 @@ namespace Orchard.Blogs.Controllers {
if (blog == null)
return new NotFoundResult();
BlogPost post = _blogPostService.Get(blog, postSlug, VersionOptions.Latest);
BlogPost post = _blogPostService.Get(postId, VersionOptions.Latest);
if (post == null)
return new NotFoundResult();

View File

@@ -111,7 +111,8 @@ namespace Orchard.Blogs.Controllers {
//todo: (heskew) need better messages
_orchardServices.Notifier.Warning(T("A different blog post is already published with this same slug."));
if (post.ContentItem.VersionRecord == null || post.ContentItem.VersionRecord.Published) {
if (post.ContentItem.VersionRecord == null || post.ContentItem.VersionRecord.Published)
{
var originalSlug = post.Slug;
//todo: (heskew) make auto-uniqueness optional
post.Slug = _routableService.GenerateUniqueSlug(post.Slug, slugsLikeThis);

View File

@@ -50,16 +50,16 @@ namespace Orchard.Blogs.Extensions {
return urlHelper.Action("Create", "BlogPostAdmin", new {blogSlug, area = "Orchard.Blogs"});
}
public static string BlogPostEdit(this UrlHelper urlHelper, string blogSlug, string postSlug) {
return urlHelper.Action("Edit", "BlogPostAdmin", new {blogSlug, postSlug, area = "Orchard.Blogs"});
public static string BlogPostEdit(this UrlHelper urlHelper, string blogSlug, int postId) {
return urlHelper.Action("Edit", "BlogPostAdmin", new {blogSlug, postId, area = "Orchard.Blogs"});
}
public static string BlogPostDelete(this UrlHelper urlHelper, string blogSlug, string postSlug) {
return urlHelper.Action("Delete", "BlogPostAdmin", new {blogSlug, postSlug, area = "Orchard.Blogs"});
public static string BlogPostDelete(this UrlHelper urlHelper, string blogSlug, int postId) {
return urlHelper.Action("Delete", "BlogPostAdmin", new {blogSlug, postId, area = "Orchard.Blogs"});
}
public static string BlogPostPublish(this UrlHelper urlHelper, string blogSlug, string postSlug) {
return urlHelper.Action("Publish", "BlogPostAdmin", new { blogSlug, postSlug, area = "Orchard.Blogs" });
public static string BlogPostPublish(this UrlHelper urlHelper, string blogSlug, int postId) {
return urlHelper.Action("Publish", "BlogPostAdmin", new { blogSlug, postId, area = "Orchard.Blogs" });
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Orchard.Blogs.Controllers;
using Orchard.Blogs.Services;
@@ -7,12 +8,24 @@ using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Records;
using Orchard.Core.Common.Services;
using Orchard.Data;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Models {
[UsedImplicitly]
public class BlogPostHandler : ContentHandler {
public BlogPostHandler(IRepository<CommonVersionRecord> commonRepository, IBlogPostService blogPostService) {
private readonly IBlogPostService _blogPostService;
private readonly IRoutableService _routableService;
private readonly IOrchardServices _orchardServices;
public BlogPostHandler(IRepository<CommonVersionRecord> commonRepository, IBlogPostService blogPostService, IRoutableService routableService, IOrchardServices orchardServices) {
_blogPostService = blogPostService;
_routableService = routableService;
_orchardServices = orchardServices;
T = NullLocalizer.Instance;
Filters.Add(new ActivatingFilter<BlogPost>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonAspect>(BlogPostDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutableAspect>(BlogPostDriver.ContentType.Name));
@@ -24,7 +37,7 @@ namespace Orchard.Blogs.Models {
// Ensure we get the "right" set of published posts for the blog
blog.ContentItem.ContentManager.Flush();
var posts = blogPostService.Get(blog, VersionOptions.Published).ToList();
var posts = _blogPostService.Get(blog, VersionOptions.Published).ToList();
blog.PostCount = posts.Count;
});
@@ -33,10 +46,30 @@ namespace Orchard.Blogs.Models {
OnVersioned<BlogPost>((context, bp1, bp2) => updateBlogPostCount(bp2.Blog));
OnRemoved<BlogPost>((context, bp) => updateBlogPostCount(bp.Blog));
OnPublished<BlogPost>((context, bp) => ProcessSlug(bp));
OnRemoved<Blog>(
(context, b) =>
blogPostService.Get(context.ContentItem.As<Blog>()).ToList().ForEach(
blogPost => context.ContentManager.Remove(blogPost.ContentItem)));
}
Localizer T { get; set; }
private void ProcessSlug(BlogPost post) {
_routableService.FillSlug(post.As<RoutableAspect>());
var slugsLikeThis = _blogPostService.Get(post.Blog, VersionOptions.Published).Where(
p => p.Slug.StartsWith(post.Slug, StringComparison.OrdinalIgnoreCase) &&
p.Id != post.Id).Select(p => p.Slug);
//todo: (heskew) need better messages
if (slugsLikeThis.Count() > 0) {
//todo: (heskew) need better messages
var originalSlug = post.Slug;
post.Slug = _routableService.GenerateUniqueSlug(post.Slug, slugsLikeThis);
_orchardServices.Notifier.Warning(T("A different blog post is already published with this same slug ({0}) so a unique slug ({1}) was generated for this post.", originalSlug, post.Slug));
}
}
}
}

View File

@@ -101,7 +101,7 @@ namespace Orchard.Blogs {
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/{blogSlug}/Posts/{postSlug}/Edit",
"Admin/Blogs/{blogSlug}/Posts/{postId}/Edit",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPostAdmin"},
@@ -117,7 +117,7 @@ namespace Orchard.Blogs {
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/{blogSlug}/Posts/{postSlug}/Delete",
"Admin/Blogs/{blogSlug}/Posts/{postId}/Delete",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPostAdmin"},
@@ -131,6 +131,22 @@ namespace Orchard.Blogs {
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/{blogSlug}/Posts/{postId}/Publish",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPostAdmin"},
{"action", "Publish"}
},
new RouteValueDictionary {
{"blogSlug", new IsBlogConstraint(_containerProvider)}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs",

View File

@@ -25,6 +25,14 @@ namespace Orchard.Blogs.Services {
SingleOrDefault().As<BlogPost>();
}
public BlogPost Get(int id) {
return Get(id, VersionOptions.Published);
}
public BlogPost Get(int id, VersionOptions versionOptions) {
return _contentManager.Get<BlogPost>(id, versionOptions);
}
public IEnumerable<BlogPost> Get(Blog blog) {
return Get(blog, VersionOptions.Published);
}

View File

@@ -7,6 +7,8 @@ namespace Orchard.Blogs.Services {
public interface IBlogPostService : IDependency {
BlogPost Get(Blog blog, string slug);
BlogPost Get(Blog blog, string slug, VersionOptions versionOptions);
BlogPost Get(int id);
BlogPost Get(int id, VersionOptions versionOptions);
IEnumerable<BlogPost> Get(Blog blog);
IEnumerable<BlogPost> Get(Blog blog, VersionOptions versionOptions);
IEnumerable<BlogPost> Get(Blog blog, ArchiveData archiveData);

View File

@@ -6,19 +6,23 @@
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Slug)) %></h2>
<h2><%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Id)) %></h2>
<div class="meta"><%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%></div>
<div class="content"><%=Model.Item.As<BodyAspect>().Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>
<ul class="actions">
<li class="construct">
<a href="<%=Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Slug) %>" class="ibutton edit" title="<%=_Encoded("Edit Post")%>"><%=_Encoded("Edit Post")%></a>
<a href="<%=Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Id) %>" class="ibutton edit" title="<%=_Encoded("Edit Post")%>"><%=_Encoded("Edit Post")%></a>
<a href="<%=Url.BlogPost(Model.Item.Blog.Slug, Model.Item.Slug) %>" class="ibutton view" title="<%=_Encoded("View Post")%>"><%=_Encoded("View Post")%></a><%
if (Model.Item.ContentItem.VersionRecord.Published == false) { // todo: (heskew) be smart about this and maybe have other contextual actions - including view/preview for view up there ^^ %>
<a href="<%=Url.BlogPostPublish(Model.Item.Blog.Slug, Model.Item.Slug) %>" class="ibutton publish" title="<%=_Encoded("Publish Post Now")%>"><%=_Encoded("Publish Post Now")%></a>
<% } %>
if (Model.Item.ContentItem.VersionRecord.Published == false) { // todo: (heskew) be smart about this and maybe have other contextual actions - including view/preview for view up there ^^
using (Html.BeginFormAntiForgeryPost(Url.BlogPostPublish(Model.Item.Blog.Slug, Model.Item.Id), FormMethod.Post, new { @class = "inline" })) { %>
<fieldset>
<button type="submit" class="ibutton publish" title="<%=_Encoded("Publish Post Now") %>"><%=_Encoded("Publish Post Now")%></button>
</fieldset><%
}
} %>
</li>
<li class="destruct">
<% using (Html.BeginFormAntiForgeryPost(Url.BlogPostDelete(Model.Item.Blog.Slug, Model.Item.Slug), FormMethod.Post, new { @class = "inline" })) { %>
<% using (Html.BeginFormAntiForgeryPost(Url.BlogPostDelete(Model.Item.Blog.Slug, Model.Item.Id), FormMethod.Post, new { @class = "inline" })) { %>
<fieldset>
<button type="submit" class="ibutton remove" title="<%=_Encoded("Remove Post") %>"><%=_Encoded("Remove Post") %></button>
</fieldset><%

View File

@@ -3,7 +3,7 @@
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><%=Html.TitleForPage(Model.Item.Title)%></h1>
<div class="manage"><a href="<%=Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Slug) %>" class="ibutton edit"><%=_Encoded("Edit") %></a></div>
<div class="manage"><a href="<%=Url.BlogPostEdit(Model.Item.Blog.Slug, Model.Item.Id) %>" class="ibutton edit"><%=_Encoded("Edit") %></a></div>
<div class="metadata">
<% if (Model.Item.Creator != null) {
%><div class="posted"><%=_Encoded("Posted by {0} {1}", Model.Item.Creator.UserName, Html.PublishedWhen(Model.Item)) %></div><%

View File

@@ -10,7 +10,7 @@
var blogPost = Model.BlogPost.Item;
var bodyViewModelModel = new BodyDisplayViewModel { BodyAspect = blogPost.ContentItem.As<BodyAspect>() };
var hasComments = blogPost.ContentItem.As<HasComments>(); %>
<div class="manage"><a href="<%=Url.BlogPostEdit(blogPost.Blog.Slug, blogPost.Slug) %>" class="ibutton edit"><%=_Encoded("edit") %></a></div>
<div class="manage"><a href="<%=Url.BlogPostEdit(blogPost.Blog.Slug, blogPost.Id) %>" class="ibutton edit"><%=_Encoded("edit") %></a></div>
<h1><%=Html.TitleForPage(blogPost.Title)%></h1>
<div class="metadata">
<% if (blogPost.Creator != null) {