bug fixes

* Display comment count in blog post (admin and front-end).
* In admin, also display # of pending comments.
* In admin, both comment count and pending count are hyperlinks to the "manage comments" page for the blog post.
* Fix a few incorrect redirect calls in the comments module
* Removed fake comment count display for aggregate blog view (we will resurrect it later with a correct implementation)

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045823
This commit is contained in:
rpaquay
2010-01-22 02:06:07 +00:00
parent 3a924430d2
commit 95d5398f50
16 changed files with 183 additions and 77 deletions

View File

@@ -9,9 +9,11 @@ if (Model.Entries.Count() > 0) { %>
// Add blog post count rendering into "meta" zone
entry.ContentItemViewModel.Zones.AddAction("meta", html => {
int draftCount = entry.TotalPostCount - entry.ContentItemViewModel.Item.PostCount;
int publishedCount = entry.TotalPostCount;
int totalPostCount = entry.TotalPostCount;
var draftText = (draftCount == 0 ? "": string.Format(" ({0} draft{1})", draftCount, draftCount == 1 ? "" : "s"));
var linkContent = _Encoded("{0} post{1}{2}", publishedCount, publishedCount == 1 ? "" : "s", draftText);
var linkContent = _Encoded("{0} post{1}{2}", totalPostCount, totalPostCount == 1 ? "" : "s", draftText);
html.ViewContext.Writer.Write(html.Link(linkContent.ToString(), Url.BlogForAdmin(entry.ContentItemViewModel.Item.Slug)));
});

View File

@@ -3,10 +3,7 @@
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.Link(Html.Encode(Model.Item.Name), Url.BlogForAdmin(Model.Item.Slug)) %></h2>
<div class="meta">
<%Html.Zone("meta"); %>
| <%=Html.Link(_Encoded("?? comments").ToString(), "") %>
</div>
<div class="meta"><%Html.Zone("meta");%></div>
<%--<p>[list of authors] [modify blog access]</p>--%>
<p><%=Html.Encode(Model.Item.Description) %></p>
<ul class="actions">

View File

@@ -119,7 +119,7 @@ namespace Orchard.Comments.Controllers {
}
catch (Exception exception) {
_notifier.Error(T("Editing comments failed: " + exception.Message));
return Index(viewModel.Options);
return RedirectToAction("Index", "Admin", new { options = viewModel.Options });
}
return RedirectToAction("Index");
@@ -187,7 +187,7 @@ namespace Orchard.Comments.Controllers {
var model = new CommentsDetailsViewModel {
Comments = entries,
Options = options,
DisplayNameForCommentedItem = _commentService.GetDisplayForCommentedContent(id).DisplayText,
DisplayNameForCommentedItem = _commentService.GetDisplayForCommentedContent(id) == null ? "" : _commentService.GetDisplayForCommentedContent(id).DisplayText,
CommentedItemId = id,
CommentsClosedOnItem = _commentService.CommentsClosedForCommentedContent(id),
};
@@ -195,7 +195,7 @@ namespace Orchard.Comments.Controllers {
}
catch (Exception exception) {
_notifier.Error(T("Listing comments failed: " + exception.Message));
return Index(new CommentIndexOptions());
return RedirectToAction("Index");
}
}
@@ -311,7 +311,7 @@ namespace Orchard.Comments.Controllers {
}
catch (Exception exception) {
_notifier.Error(T("Editing comment failed: " + exception.Message));
return Index(new CommentIndexOptions());
return RedirectToAction("Index");
}
}
@@ -349,7 +349,7 @@ namespace Orchard.Comments.Controllers {
if (!String.IsNullOrEmpty(returnUrl)) {
return Redirect(returnUrl);
}
return Index(new CommentIndexOptions());
return RedirectToAction("Index");
}
}

View File

@@ -0,0 +1,45 @@
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Mvc.Html;
namespace Orchard.Comments.Extensions {
public static class HtmlHelperExtensions {
public static MvcHtmlString CommentSummaryLinks(this HtmlHelper html, Localizer T, ContentItem item, int commentCount, int pendingCount) {
string commentText = "";
if (item.Id != 0) {
if (commentCount == 0) {
commentText += html.Encode(T("no comments"));
}
else {
commentText +=
html.ActionLink(
T("{0} comment{1}", commentCount, commentCount == 1 ? "" : "s").ToString(),
"Details",
new {
Area = "Orchard.Comments",
Controller = "Admin",
id = item.Id,
returnUrl = html.ViewContext.HttpContext.Request.Url
});
}
if (pendingCount > 0) {
commentText += " - ";
commentText += html.ActionLink(T("{0} pending", pendingCount).ToString(),
"Details",
new {
Area = "Orchard.Comments",
Controller = "Admin",
id = item.Id,
returnUrl = html.ViewContext.HttpContext.Request.Url
});
}
}
return MvcHtmlString.Create(commentText);
}
}
}

View File

@@ -1,37 +0,0 @@
using System.Linq;
using JetBrains.Annotations;
using Orchard.Comments.Services;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Comments.Models {
[UsedImplicitly]
public class HasCommentsHandler : ContentHandler {
public HasCommentsHandler(
IRepository<Comment> commentsRepository,
IRepository<HasCommentsRecord> hasCommentsRepository,
ICommentService commentService) {
Filters.Add(new ActivatingFilter<HasComments>("sandboxpage"));
Filters.Add(new ActivatingFilter<HasComments>("blogpost"));
Filters.Add(new StorageFilter<HasCommentsRecord>(hasCommentsRepository) );
OnActivated<HasComments>((ctx, x) => {
x.CommentsActive = true;
x.CommentsShown = true;
});
OnLoading<HasComments>((context, comments) => {
comments.Comments = commentsRepository.Fetch(x => x.CommentedOn == context.ContentItem.Id && x.Status == CommentStatus.Approved);
});
OnRemoved<HasComments>((context, c) => {
if (context.ContentType == "blogpost" || context.ContentType == "sandboxpage") {
//TODO: (erikpo) Once comments are content items, replace the following repository delete call to a content manager remove call
commentService.GetCommentsForCommentedContent(context.ContentItem.Id).ToList().ForEach(
commentsRepository.Delete);
}
});
}
}
}

View File

@@ -6,10 +6,15 @@ using Orchard.ContentManagement.Records;
namespace Orchard.Comments.Models {
public class HasComments : ContentPart<HasCommentsRecord> {
public HasComments() {
Comments = new List<Comment>();
PendingComments = new List<Comment>();
}
public int CommentCount { get { return Comments.Count(); } }
public int CommentCount { get { return Comments.Count; } }
public IEnumerable<Comment> Comments { get; set; }
public IList<Comment> Comments { get; set; }
public IList<Comment> PendingComments { get; set; }
public bool CommentsShown {
get { return Record.CommentsShown; }

View File

@@ -1,8 +1,10 @@
using Orchard.Comments.Models;
using JetBrains.Annotations;
using Orchard.Comments.ViewModels;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
namespace Orchard.Comments.Controllers {
namespace Orchard.Comments.Models {
[UsedImplicitly]
public class HasCommentsDriver : ContentPartDriver<HasComments> {
protected override DriverResult Display(HasComments part, string displayType) {
if (part.CommentsShown == false) {
@@ -17,12 +19,18 @@ namespace Orchard.Comments.Controllers {
// ContentPartTemplate(part, "Parts/Comments.HasComments").Location("body", "below.5"));
return ContentPartTemplate(part, "Parts/Comments.HasComments").Location("primary", "after.5");
}
if (displayType.Contains("Summary")) {
return ContentPartTemplate(part, "Parts/Comments.Count").Location("meta");
else if (displayType == "SummaryAdmin") {
var model = new CommentCountViewModel(part);
return ContentPartTemplate(model, "Parts/Comments.CountAdmin").Location("meta");
}
else if (displayType.Contains("Summary")) {
var model = new CommentCountViewModel(part);
return ContentPartTemplate(model, "Parts/Comments.Count").Location("meta");
}
else {
var model = new CommentCountViewModel(part);
return ContentPartTemplate(model, "Parts/Comments.Count").Location("primary", "before.5");
}
return ContentPartTemplate(part, "Parts/Comments.Count").Location("primary", "before.5");
}
protected override DriverResult Editor(HasComments part) {
@@ -34,4 +42,4 @@ namespace Orchard.Comments.Controllers {
return ContentPartTemplate(part, "Parts/Comments.HasComments").Location("primary", "99");
}
}
}
}

View File

@@ -0,0 +1,65 @@
using System.Linq;
using JetBrains.Annotations;
using Orchard.Comments.Services;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Comments.Models {
[UsedImplicitly]
public class HasCommentsHandler : ContentHandler {
public HasCommentsHandler(
IRepository<Comment> commentsRepository,
IRepository<HasCommentsRecord> hasCommentsRepository,
ICommentService commentService) {
Filters.Add(new ActivatingFilter<HasComments>("sandboxpage"));
Filters.Add(new ActivatingFilter<HasComments>("blogpost"));
Filters.Add(new StorageFilter<HasCommentsRecord>(hasCommentsRepository));
OnActivated<HasComments>((ctx, x) => {
x.CommentsActive = true;
x.CommentsShown = true;
});
OnLoading<HasComments>((context, comments) => {
comments.Comments = commentsRepository.Fetch(x => x.CommentedOn == context.ContentItem.Id && x.Status == CommentStatus.Approved).ToList();
comments.PendingComments = commentsRepository.Fetch(x => x.CommentedOn == context.ContentItem.Id && x.Status == CommentStatus.Pending).ToList();
});
OnRemoved<HasComments>((context, c) => {
//TODO: (erikpo) Once comments are content items, replace the following repository delete call to a content manager remove call
var comments = commentService.GetCommentsForCommentedContent(context.ContentItem.Id).ToList();
comments.ForEach(commentsRepository.Delete);
});
}
}
#if false
[UsedImplicitly]
public class HasCommentsContainerHandler : ContentHandler {
public HasCommentsContainerHandler() {
Filters.Add(new ActivatingFilter<HasCommentsContainer>("blog"));
}
}
public class HasCommentsContainer : ContentPart {
}
public class HasCommentsContainerDriver : ContentPartDriver<HasCommentsContainer> {
protected override DriverResult Display(HasCommentsContainer part, string displayType) {
if (displayType.Contains("Summary")) {
// Find all contents item with this part as the container
var parts = part.ContentItem.ContentManager.Query()
.Where<CommonRecord>(rec => rec.Container == part.ContentItem.Record).List();
// Count comments and create template
int count = parts.Aggregate(0, (seed, item) => item.Has<HasComments>() ? item.As<HasComments>().CommentCount : 0);
var model = new CommentCountViewModel { Item = part.ContentItem, CommentCount = count };
return ContentPartTemplate(model, "Parts/Comments.Count").Location("meta");
}
return null;
}
}
#endif
}

View File

@@ -67,15 +67,17 @@
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\HasCommentsDriver.cs" />
<Compile Include="Extensions\HtmlHelperExtensions.cs" />
<Compile Include="Models\HasCommentsDriver.cs" />
<Compile Include="Feeds\CommentedOnContainerFeedQuery.cs" />
<Compile Include="Feeds\CommentedOnFeedQuery.cs" />
<Compile Include="Feeds\CommentFeedItemBuilder.cs" />
<Compile Include="Models\Comment.cs" />
<Compile Include="ViewModels\CommentCountViewModel.cs" />
<Compile Include="Models\CommentSettings.cs" />
<Compile Include="Models\CommentSettingsHandler.cs" />
<Compile Include="Models\CommentSettingsRecord.cs" />
<Compile Include="Models\CommentsHandler.cs" />
<Compile Include="Models\HasCommentsHandler.cs" />
<Compile Include="Models\HasComments.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -95,6 +97,7 @@
<Content Include="Views\Admin\Index.aspx" />
<Content Include="Views\DisplayTemplates\Parts\Comments.HasComments.ascx" />
<Content Include="Views\DisplayTemplates\Parts\Comments.Count.ascx" />
<Content Include="Views\DisplayTemplates\Parts\Comments.CountAdmin.ascx" />
<Content Include="Views\EditorTemplates\Parts\Comments.SiteSettings.ascx" />
<Content Include="Views\EditorTemplates\Parts\Comments.HasComments.ascx" />
<Content Include="Views\ListOfComments.ascx" />

View File

@@ -0,0 +1,16 @@
using Orchard.Comments.Models;
using Orchard.ContentManagement;
namespace Orchard.Comments.ViewModels {
public class CommentCountViewModel {
public CommentCountViewModel(HasComments part) {
Item = part.ContentItem;
CommentCount = part.Comments.Count;
PendingCount = part.PendingComments.Count;
}
public ContentItem Item { get; set; }
public int CommentCount { get; set; }
public int PendingCount { get; set; }
}
}

View File

@@ -1,3 +1,3 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<HasComments>" %>
<%@ Import Namespace="Orchard.Comments.Models"%>
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<CommentCountViewModel>" %>
<%@ Import Namespace="Orchard.Comments.ViewModels"%>
<span class="commentcount"><%=_Encoded("{0} Comment{1}", Model.CommentCount, Model.CommentCount == 1 ? "" : "s")%></span>

View File

@@ -0,0 +1,4 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<CommentCountViewModel>" %>
<%@ Import Namespace="Orchard.Comments.Extensions"%>
<%@ Import Namespace="Orchard.Comments.ViewModels"%>
<span class="commentcount"><%=Html.CommentSummaryLinks(T, Model.Item, Model.CommentCount, Model.PendingCount)%></span>

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<HasComments>" %>
<%@ Import Namespace="Orchard.Comments.Models"%>
<h2 id="comments"><%=_Encoded("{0} Comment{1}", Model.CommentCount, Model.CommentCount == 1 ? "" : "s") %></h2><%
if (Model.CommentCount > 0) { Html.RenderPartial("ListOfComments", Model.Comments); }
<h2 id="comments"><%=_Encoded("{0} Comment{1}", Model.Comments.Count, Model.Comments.Count == 1 ? "" : "s")%></h2><%
if (Model.Comments.Count > 0) { Html.RenderPartial("ListOfComments", Model.Comments); }
if (Model.CommentsActive == false) { %>
<p><%=_Encoded("Comments have been disabled for this content.") %></p><%
} else { %>

View File

@@ -1,19 +1,17 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<HasComments>" %>
<%@ Import Namespace="Orchard.Comments.Extensions"%>
<%@ Import Namespace="Orchard.Localization" %>
<%@ Import Namespace="Orchard.Comments.Models" %>
<fieldset>
<%-- todo: (heskew) pull the legend and put the link to the comments elsewhere? --%>
<legend><%=Model.ContentItem.Id != 0
? T("Comments {0} - <a href=\"#\">?? pending</a>", Html.ActionLink(
T("{0} comment{1}", Model.CommentCount, Model.CommentCount == 1 ? "" : "s").ToString(),
"Details",
new { Area = "Orchard.Comments", Controller = "Admin", id = Model.ContentItem.Id, returnUrl = Context.Request.Url }))
: T("Comments")%></legend>
<%--
<legend><%=_Encoded("Comments")%> <%=Html.CommentSummaryLinks(T, Model.ContentItem, Model.Comments.Count, Model.PendingComments.Count)%></legend>
<%--
todo: (heskew) can get into a weird state if this is disabled but comments are active so, yeah, comment settings on a content item need to be hashed out
<%=Html.EditorFor(m => m.CommentsShown) %>
<label class="forcheckbox" for="CommentsShown"><%=T("Comments are shown. Existing comments are displayed.") %></label>
--%>
<%=Html.EditorFor(m => m.CommentsActive) %>
<label class="forcheckbox" for="CommentsActive"><%=T("Allow new comments") %></label>
<span class="hint forcheckbox"><%=T("Enable to show the comment form. Disabling still allows the existing comments to be shown but does not allow the conversation to continue.")%></span>
</fieldset>
<label class="forcheckbox" for="CommentsActive">
<%=T("Allow new comments") %></label> <span class="hint forcheckbox">
<%=T("Enable to show the comment form. Disabling still allows the existing comments to be shown but does not allow the conversation to continue.")%></span>
</fieldset>

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<HasComments>" %>
<%@ Import Namespace="Orchard.Comments.Models"%>
<h2 id="comments"><%=_Encoded("{0} Comment{1}", Model.CommentCount, Model.CommentCount == 1 ? "" : "s") %></h2><%
if (Model.CommentCount > 0) { Html.RenderPartial("ListOfComments", Model.Comments); }
<h2 id="comments"><%=_Encoded("{0} Comment{1}", Model.Comments.Count, Model.Comments.Count == 1 ? "" : "s")%></h2><%
if (Model.Comments.Count > 0) { Html.RenderPartial("ListOfComments", Model.Comments); }
if (Model.CommentsActive == false) { %>
<p><%=_Encoded("Comments have been disabled for this content.") %></p><%
} else { %>

View File

@@ -16,7 +16,7 @@
<% if (blogPost.Creator != null) {
%><div class="posted"><%=_Encoded("Posted by {0} {1}", blogPost.Creator.UserName, Html.PublishedWhen(blogPost))%></div><%
} %>
<%=Html.Link(T(hasComments.CommentCount == 1 ? "{0} comment" : "{0} comments", hasComments.CommentCount).ToString(), "#comments")%>
<%=Html.Link(T(hasComments.Comments.Count == 1 ? "{0} comment" : "{0} comments", hasComments.Comments.Count).ToString(), "#comments")%>
</div>
<%=Html.DisplayFor(m => bodyViewModelModel, "Parts/Common.Body")%>
<%=Html.DisplayFor(m => hasComments, "Parts/Comments.HasComments", "") %>