mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-01-22 21:02:08 +08:00
Make "Comment" a content type and enable comment count at blog container level
* Fix bug where closing comments multiple times would result in inconsistent database. * Rename a few classes/fields in Comments module to follow coding convention (Record suffix, Utc suffix for dates) * Move classes to their own file * Create a HasCommentContainer handler to enable displaying comment counts (approved/pending) for container (i.e. blog) --HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045899
This commit is contained in:
@@ -3,5 +3,5 @@
|
||||
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
|
||||
<%@ Import Namespace="Orchard.Blogs.Models"%>
|
||||
<h2><%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %></h2>
|
||||
<div class="blog metadata"><a href="<%=Url.Blog(Model.Item.Slug) %>"><%=_Encoded("{0} post{1}", Model.Item.PostCount, Model.Item.PostCount == 1 ? "" : "s")%></a></div>
|
||||
<div class="blog metadata"><a href="<%=Url.Blog(Model.Item.Slug) %>"><%Html.Zone("meta");%><%--<%=_Encoded("{0} post{1}", Model.Item.PostCount, Model.Item.PostCount == 1 ? "" : "s")%>--%></a></div>
|
||||
<p><%=Html.Encode(Model.Item.Description) %></p>
|
||||
@@ -18,11 +18,13 @@ namespace Orchard.Comments.Controllers {
|
||||
[ValidateInput(false)]
|
||||
public class AdminController : Controller {
|
||||
private readonly ICommentService _commentService;
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IAuthorizer _authorizer;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public AdminController(ICommentService commentService, INotifier notifier, IAuthorizer authorizer) {
|
||||
public AdminController(ICommentService commentService, IContentManager contentManager, INotifier notifier, IAuthorizer authorizer) {
|
||||
_commentService = commentService;
|
||||
_contentManager = contentManager;
|
||||
_authorizer = authorizer;
|
||||
_notifier = notifier;
|
||||
Logger = NullLogger.Instance;
|
||||
@@ -59,7 +61,7 @@ namespace Orchard.Comments.Controllers {
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var entries = comments.Select(comment => CreateCommentEntry(comment)).ToList();
|
||||
var entries = comments.Select(comment => CreateCommentEntry(comment.Record)).ToList();
|
||||
var model = new CommentsIndexViewModel {Comments = entries, Options = options};
|
||||
return View(model);
|
||||
}
|
||||
@@ -138,16 +140,19 @@ namespace Orchard.Comments.Controllers {
|
||||
if (!_authorizer.Authorize(Permissions.AddComment, T("Couldn't add comment")))
|
||||
return new HttpUnauthorizedResult();
|
||||
}
|
||||
Comment comment = new Comment {
|
||||
|
||||
CommentRecord commentRecord = new CommentRecord {
|
||||
Author = viewModel.Name,
|
||||
CommentDate = DateTime.UtcNow,
|
||||
CommentDateUtc = DateTime.UtcNow,
|
||||
CommentText = viewModel.CommentText,
|
||||
Email = viewModel.Email,
|
||||
SiteName = viewModel.SiteName,
|
||||
UserName = CurrentUser == null ? "Anonymous" : CurrentUser.UserName,
|
||||
CommentedOn = viewModel.CommentedOn,
|
||||
};
|
||||
_commentService.CreateComment(comment);
|
||||
|
||||
var comment = _commentService.CreateComment(commentRecord);
|
||||
|
||||
if (!String.IsNullOrEmpty(returnUrl)) {
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
@@ -183,7 +188,7 @@ namespace Orchard.Comments.Controllers {
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var entries = comments.Select(comment => CreateCommentEntry(comment)).ToList();
|
||||
var entries = comments.Select(comment => CreateCommentEntry(comment.Record)).ToList();
|
||||
var model = new CommentsDetailsViewModel {
|
||||
Comments = entries,
|
||||
Options = options,
|
||||
@@ -299,12 +304,12 @@ namespace Orchard.Comments.Controllers {
|
||||
try {
|
||||
Comment comment = _commentService.GetComment(id);
|
||||
var viewModel = new CommentsEditViewModel {
|
||||
CommentText = comment.CommentText,
|
||||
Email = comment.Email,
|
||||
Id = comment.Id,
|
||||
Name = comment.Author,
|
||||
SiteName = comment.SiteName,
|
||||
Status = comment.Status,
|
||||
CommentText = comment.Record.CommentText,
|
||||
Email = comment.Record.Email,
|
||||
Id = comment.Record.Id,
|
||||
Name = comment.Record.Author,
|
||||
SiteName = comment.Record.SiteName,
|
||||
Status = comment.Record.Status,
|
||||
};
|
||||
return View(viewModel);
|
||||
|
||||
@@ -337,8 +342,10 @@ namespace Orchard.Comments.Controllers {
|
||||
try {
|
||||
if (!_authorizer.Authorize(Permissions.ManageComments, T("Couldn't delete comment")))
|
||||
return new HttpUnauthorizedResult();
|
||||
int commentedOn = _commentService.GetComment(id).CommentedOn;
|
||||
|
||||
int commentedOn = _commentService.GetComment(id).Record.CommentedOn;
|
||||
_commentService.DeleteComment(id);
|
||||
|
||||
if (!String.IsNullOrEmpty(returnUrl)) {
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
@@ -353,7 +360,7 @@ namespace Orchard.Comments.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
private CommentEntry CreateCommentEntry(Comment comment) {
|
||||
private CommentEntry CreateCommentEntry(CommentRecord comment) {
|
||||
return new CommentEntry {
|
||||
Comment = comment,
|
||||
CommentedOn = _commentService.GetDisplayForCommentedContent(comment.CommentedOn).DisplayText,
|
||||
|
||||
@@ -2,7 +2,6 @@ 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 {
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Orchard.Comments.Feeds {
|
||||
Localizer T { get; set; }
|
||||
|
||||
public void Populate(FeedContext context) {
|
||||
foreach (var feedItem in context.Response.Items.OfType<FeedItem<Comment>>()) {
|
||||
foreach (var feedItem in context.Response.Items.OfType<FeedItem<CommentRecord>>()) {
|
||||
var comment = feedItem.Item;
|
||||
var commentedOn = _contentManager.Get(feedItem.Item.CommentedOn);
|
||||
var commentedOnInspector = new ItemInspector(
|
||||
@@ -47,7 +47,7 @@ namespace Orchard.Comments.Feeds {
|
||||
feedItem.Element.SetElementValue("title", title);
|
||||
feedItem.Element.Add(link);
|
||||
feedItem.Element.SetElementValue("description", comment.CommentText);
|
||||
feedItem.Element.SetElementValue("pubDate", comment.CommentDate);//TODO: format
|
||||
feedItem.Element.SetElementValue("pubDate", comment.CommentDateUtc);//TODO: format
|
||||
feedItem.Element.Add(guid);
|
||||
}
|
||||
else {
|
||||
@@ -59,7 +59,7 @@ namespace Orchard.Comments.Feeds {
|
||||
context.Builder.AddProperty(context, feedItem, "title", title.ToString());
|
||||
context.Builder.AddProperty(context, feedItem, "description", comment.CommentText);
|
||||
|
||||
context.Builder.AddProperty(context, feedItem, "published-date", Convert.ToString(comment.CommentDate)); // format? cvt to generic T?
|
||||
context.Builder.AddProperty(context, feedItem, "published-date", Convert.ToString(comment.CommentDateUtc)); // format? cvt to generic T?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Comments.Models;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Core.Feeds;
|
||||
using Orchard.Core.Feeds.Models;
|
||||
using Orchard.Data;
|
||||
@@ -7,11 +8,10 @@ using Orchard.Data;
|
||||
namespace Orchard.Comments.Feeds {
|
||||
[UsedImplicitly]
|
||||
public class CommentedOnContainerFeedQuery : IFeedQueryProvider, IFeedQuery {
|
||||
private readonly IRepository<Comment> _commentRepository;
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
public CommentedOnContainerFeedQuery(
|
||||
IRepository<Comment> commentRepository) {
|
||||
_commentRepository = commentRepository;
|
||||
public CommentedOnContainerFeedQuery(IContentManager contentManager) {
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public FeedQueryMatch Match(FeedContext context) {
|
||||
@@ -29,10 +29,11 @@ namespace Orchard.Comments.Feeds {
|
||||
if (limitValue != null)
|
||||
limit = (int)limitValue.ConvertTo(typeof(int));
|
||||
|
||||
var comments = _commentRepository.Fetch(
|
||||
x => x.CommentedOnContainer == commentedOnContainer && x.Status == CommentStatus.Approved,
|
||||
o => o.Desc(x => x.CommentDate),
|
||||
0, limit);
|
||||
var comments = _contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(x => x.CommentedOnContainer == commentedOnContainer && x.Status == CommentStatus.Approved)
|
||||
.OrderByDescending(x => x.CommentDateUtc)
|
||||
.Slice(0, limit);
|
||||
|
||||
foreach (var comment in comments) {
|
||||
context.Builder.AddItem(context, comment);
|
||||
|
||||
@@ -7,10 +7,10 @@ using Orchard.Data;
|
||||
namespace Orchard.Comments.Feeds {
|
||||
[UsedImplicitly]
|
||||
public class CommentedOnFeedQuery : IFeedQueryProvider, IFeedQuery {
|
||||
private readonly IRepository<Comment> _commentRepository;
|
||||
private readonly IRepository<CommentRecord> _commentRepository;
|
||||
|
||||
public CommentedOnFeedQuery(
|
||||
IRepository<Comment> commentRepository) {
|
||||
IRepository<CommentRecord> commentRepository) {
|
||||
_commentRepository = commentRepository;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Orchard.Comments.Feeds {
|
||||
|
||||
var comments = _commentRepository.Fetch(
|
||||
x => x.CommentedOn == commentedOn && x.Status == CommentStatus.Approved,
|
||||
o => o.Desc(x => x.CommentDate),
|
||||
o => o.Desc(x => x.CommentDateUtc),
|
||||
0, limit);
|
||||
|
||||
foreach (var comment in comments) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Orchard.Comments.Models {
|
||||
public class ClosedCommentsRecord {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual int ContentItemId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,6 @@
|
||||
using System;
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
public class Comment {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual string Author { get; set; }
|
||||
public virtual string SiteName { get; set; }
|
||||
public virtual string UserName { get; set; }
|
||||
public virtual string Email { get; set; }
|
||||
public virtual CommentStatus Status { get; set; }
|
||||
public virtual DateTime CommentDate { get; set; }
|
||||
public virtual string CommentText { get; set; }
|
||||
public virtual int CommentedOn { get; set; }
|
||||
public virtual int CommentedOnContainer { get; set; }
|
||||
public class Comment : ContentPart<CommentRecord> {
|
||||
}
|
||||
|
||||
public class ClosedComments {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual int ContentItemId { get; set; }
|
||||
}
|
||||
|
||||
public enum CommentStatus {
|
||||
Pending,
|
||||
Approved,
|
||||
Spam
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
[UsedImplicitly]
|
||||
public class CommentDriver : ContentItemDriver<Comment> {
|
||||
public readonly static ContentType ContentType = new ContentType {
|
||||
Name = "comment",
|
||||
DisplayName = "Comment"
|
||||
};
|
||||
|
||||
protected override ContentType GetContentType() {
|
||||
return ContentType;
|
||||
}
|
||||
|
||||
protected override string Prefix { get { return ""; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Data;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
[UsedImplicitly]
|
||||
public class CommentHandler : ContentHandler {
|
||||
public CommentHandler(IRepository<CommentRecord> commentsRepository) {
|
||||
Filters.Add(new ActivatingFilter<Comment>(CommentDriver.ContentType.Name));
|
||||
Filters.Add(new ActivatingFilter<CommonAspect>(CommentDriver.ContentType.Name));
|
||||
Filters.Add(new StorageFilter<CommentRecord>(commentsRepository));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
public class CommentRecord : ContentPartRecord {
|
||||
public virtual string Author { get; set; }
|
||||
public virtual string SiteName { get; set; }
|
||||
public virtual string UserName { get; set; }
|
||||
public virtual string Email { get; set; }
|
||||
public virtual CommentStatus Status { get; set; }
|
||||
public virtual DateTime CommentDateUtc { get; set; }
|
||||
public virtual string CommentText { get; set; }
|
||||
public virtual int CommentedOn { get; set; }
|
||||
public virtual int CommentedOnContainer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Orchard.Comments.Models {
|
||||
public enum CommentStatus {
|
||||
Pending,
|
||||
Approved,
|
||||
Spam
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
public class HasComments : ContentPart<HasCommentsRecord> {
|
||||
@@ -11,8 +10,6 @@ namespace Orchard.Comments.Models {
|
||||
PendingComments = new List<Comment>();
|
||||
}
|
||||
|
||||
public int CommentCount { get { return Comments.Count; } }
|
||||
|
||||
public IList<Comment> Comments { get; set; }
|
||||
public IList<Comment> PendingComments { get; set; }
|
||||
|
||||
@@ -26,9 +23,4 @@ namespace Orchard.Comments.Models {
|
||||
set { Record.CommentsActive = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class HasCommentsRecord : ContentPartRecord {
|
||||
public virtual bool CommentsShown { get; set; }
|
||||
public virtual bool CommentsActive { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
public class HasCommentsContainer : ContentPart {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Comments.ViewModels;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Core.Common.Records;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
[UsedImplicitly]
|
||||
public class HasCommentsContainerDriver : ContentPartDriver<HasCommentsContainer> {
|
||||
protected override DriverResult Display(HasCommentsContainer part, string displayType) {
|
||||
if (displayType == "SummaryAdmin") {
|
||||
return ContentPartTemplate(CreateViewModel(part.ContentItem), "Parts/Comments.CountAdmin").Location("meta");
|
||||
}
|
||||
else if (displayType.Contains("Summary")) {
|
||||
return ContentPartTemplate(CreateViewModel(part.ContentItem), "Parts/Comments.Count").Location("meta");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CommentCountViewModel CreateViewModel(ContentItem contentItem) {
|
||||
// Find all contents item with this part as the container
|
||||
var parts = contentItem.ContentManager.Query()
|
||||
.Where<CommonRecord>(rec => rec.Container == contentItem.Record).List();
|
||||
|
||||
// Count comments and create template
|
||||
int count = parts.Aggregate(0, (seed, item) => seed + (ContentExtensions.Has<HasComments>(item) ? ContentExtensions.As<HasComments>(item).Comments.Count : 0));
|
||||
int pendingCount = parts.Aggregate(0, (seed, item) => seed + (item.Has<HasComments>() ? item.As<HasComments>().PendingComments.Count : 0));
|
||||
|
||||
return new CommentCountViewModel { Item = contentItem, CommentCount = count, PendingCount = pendingCount};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
[UsedImplicitly]
|
||||
public class HasCommentsContainerHandler : ContentHandler {
|
||||
public HasCommentsContainerHandler() {
|
||||
Filters.Add(new ActivatingFilter<HasCommentsContainer>("blog"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,4 +42,4 @@ namespace Orchard.Comments.Models {
|
||||
return ContentPartTemplate(part, "Parts/Comments.HasComments").Location("primary", "99");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Comments.Services;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Data;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
|
||||
@@ -8,7 +9,7 @@ namespace Orchard.Comments.Models {
|
||||
[UsedImplicitly]
|
||||
public class HasCommentsHandler : ContentHandler {
|
||||
public HasCommentsHandler(
|
||||
IRepository<Comment> commentsRepository,
|
||||
IContentManager contentManager,
|
||||
IRepository<HasCommentsRecord> hasCommentsRepository,
|
||||
ICommentService commentService) {
|
||||
|
||||
@@ -22,43 +23,25 @@ namespace Orchard.Comments.Models {
|
||||
});
|
||||
|
||||
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();
|
||||
//TODO: lazy loading?
|
||||
comments.Comments = contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(x => x.CommentedOn == context.ContentItem.Id && x.Status == CommentStatus.Approved)
|
||||
.List().ToList();
|
||||
|
||||
//TODO: lazy loading?
|
||||
comments.PendingComments = contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(x => x.CommentedOn == context.ContentItem.Id && x.Status == CommentStatus.Pending)
|
||||
.List().ToList();
|
||||
});
|
||||
|
||||
OnRemoved<HasComments>(
|
||||
(context, c) =>
|
||||
commentService.GetCommentsForCommentedContent(context.ContentItem.Id).ToList().ForEach(
|
||||
commentsRepository.Delete));
|
||||
(context, c) => {
|
||||
foreach (var comment in commentService.GetCommentsForCommentedContent(context.ContentItem.Id)) {
|
||||
contentManager.Remove(comment.ContentItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Comments.Models {
|
||||
public class HasCommentsRecord : ContentPartRecord {
|
||||
public virtual bool CommentsShown { get; set; }
|
||||
public virtual bool CommentsActive { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -68,11 +68,20 @@
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Extensions\HtmlHelperExtensions.cs" />
|
||||
<Compile Include="Models\ClosedCommentsRecord.cs" />
|
||||
<Compile Include="Models\Comment.cs" />
|
||||
<Compile Include="Models\CommentDriver.cs" />
|
||||
<Compile Include="Models\CommentHandler.cs" />
|
||||
<Compile Include="Models\CommentStatus.cs" />
|
||||
<Compile Include="Models\HasCommentsContainer.cs" />
|
||||
<Compile Include="Models\HasCommentsContainerDriver.cs" />
|
||||
<Compile Include="Models\HasCommentsContainerHandler.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="Models\CommentRecord.cs" />
|
||||
<Compile Include="Models\HasCommentsRecord.cs" />
|
||||
<Compile Include="ViewModels\CommentCountViewModel.cs" />
|
||||
<Compile Include="Models\CommentSettings.cs" />
|
||||
<Compile Include="Models\CommentSettingsHandler.cs" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Castle.Core;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Comments.Models;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
@@ -18,7 +19,7 @@ namespace Orchard.Comments.Services {
|
||||
IEnumerable<Comment> GetCommentsForCommentedContent(int id, CommentStatus status);
|
||||
Comment GetComment(int id);
|
||||
ContentItemMetadata GetDisplayForCommentedContent(int id);
|
||||
void CreateComment(Comment comment);
|
||||
Comment CreateComment(CommentRecord commentRecord);
|
||||
void UpdateComment(int id, string name, string email, string siteName, string commentText, CommentStatus status);
|
||||
void ApproveComment(int commentId);
|
||||
void PendComment(int commentId);
|
||||
@@ -29,29 +30,22 @@ namespace Orchard.Comments.Services {
|
||||
void EnableCommentsForCommentedContent(int id);
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public class CommentService : ICommentService {
|
||||
private readonly IRepository<Comment> _commentRepository;
|
||||
private readonly IRepository<ClosedComments> _closedCommentsRepository;
|
||||
private readonly IRepository<HasCommentsRecord> _hasCommentsRepository;
|
||||
private readonly IRepository<ClosedCommentsRecord> _closedCommentsRepository;
|
||||
private readonly ICommentValidator _commentValidator;
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IAuthorizer _authorizer;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public CommentService(IRepository<Comment> commentRepository,
|
||||
IRepository<ClosedComments> closedCommentsRepository,
|
||||
public CommentService(IRepository<CommentRecord> commentRepository,
|
||||
IRepository<ClosedCommentsRecord> closedCommentsRepository,
|
||||
IRepository<HasCommentsRecord> hasCommentsRepository,
|
||||
ICommentValidator commentValidator,
|
||||
IContentManager contentManager,
|
||||
IAuthorizer authorizer,
|
||||
INotifier notifier) {
|
||||
_commentRepository = commentRepository;
|
||||
_closedCommentsRepository = closedCommentsRepository;
|
||||
_hasCommentsRepository = hasCommentsRepository;
|
||||
_commentValidator = commentValidator;
|
||||
_contentManager = contentManager;
|
||||
_authorizer = authorizer;
|
||||
_notifier = notifier;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
@@ -62,23 +56,35 @@ namespace Orchard.Comments.Services {
|
||||
#region Implementation of ICommentService
|
||||
|
||||
public IEnumerable<Comment> GetComments() {
|
||||
return from comment in _commentRepository.Table.ToList() select comment;
|
||||
return _contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.List();
|
||||
}
|
||||
|
||||
public IEnumerable<Comment> GetComments(CommentStatus status) {
|
||||
return from comment in _commentRepository.Table.ToList() where comment.Status == status select comment;
|
||||
return _contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(c => c.Status == status)
|
||||
.List();
|
||||
}
|
||||
|
||||
public IEnumerable<Comment> GetCommentsForCommentedContent(int id) {
|
||||
return from comment in _commentRepository.Table.ToList() where comment.CommentedOn == id select comment;
|
||||
return _contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(c => c.CommentedOn == id || c.CommentedOnContainer == id)
|
||||
.List();
|
||||
}
|
||||
|
||||
public IEnumerable<Comment> GetCommentsForCommentedContent(int id, CommentStatus status) {
|
||||
return from comment in _commentRepository.Table.ToList() where comment.CommentedOn == id && comment.Status == status select comment;
|
||||
return _contentManager
|
||||
.Query<Comment, CommentRecord>()
|
||||
.Where(c => c.CommentedOn == id || c.CommentedOnContainer == id)
|
||||
.Where(ctx => ctx.Status == status)
|
||||
.List();
|
||||
}
|
||||
|
||||
public Comment GetComment(int id) {
|
||||
return _commentRepository.Get(id);
|
||||
return _contentManager.Get<Comment>(id);
|
||||
}
|
||||
|
||||
public ContentItemMetadata GetDisplayForCommentedContent(int id) {
|
||||
@@ -88,59 +94,71 @@ namespace Orchard.Comments.Services {
|
||||
return _contentManager.GetItemMetadata(content);
|
||||
}
|
||||
|
||||
public void CreateComment(Comment comment) {
|
||||
comment.Status = _commentValidator.ValidateComment(comment) ? CommentStatus.Pending : CommentStatus.Spam;
|
||||
public Comment CreateComment(CommentRecord commentRecord) {
|
||||
var comment = _contentManager.Create<Comment>("comment");
|
||||
|
||||
//TODO:(rpaquay) CommentRecord should never be used as "data object"
|
||||
comment.Record.Author = commentRecord.Author;
|
||||
comment.Record.CommentDateUtc = commentRecord.CommentDateUtc;
|
||||
comment.Record.CommentText = commentRecord.CommentText;
|
||||
comment.Record.Email = commentRecord.Email;
|
||||
comment.Record.SiteName = commentRecord.SiteName;
|
||||
comment.Record.UserName = commentRecord.UserName;
|
||||
comment.Record.CommentedOn = commentRecord.CommentedOn;
|
||||
|
||||
comment.Record.Status = _commentValidator.ValidateComment(commentRecord) ? CommentStatus.Pending : CommentStatus.Spam;
|
||||
|
||||
// store id of the next layer for large-grained operations, e.g. rss on blog
|
||||
var commentedOn = _contentManager.Get<ICommonAspect>(comment.CommentedOn);
|
||||
//TODO:(rpaquay) Get rid of this (comment aspect takes care of container)
|
||||
var commentedOn = _contentManager.Get<ICommonAspect>(comment.Record.CommentedOn);
|
||||
if (commentedOn != null && commentedOn.Container != null) {
|
||||
comment.CommentedOnContainer = commentedOn.Container.ContentItem.Id;
|
||||
comment.Record.CommentedOnContainer = commentedOn.Container.ContentItem.Id;
|
||||
}
|
||||
|
||||
_commentRepository.Create(comment);
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void UpdateComment(int id, string name, string email, string siteName, string commentText, CommentStatus status) {
|
||||
Comment comment = GetComment(id);
|
||||
comment.Author = name;
|
||||
comment.Email = email;
|
||||
comment.SiteName = siteName;
|
||||
comment.CommentText = commentText;
|
||||
comment.Status = status;
|
||||
comment.Record.Author = name;
|
||||
comment.Record.Email = email;
|
||||
comment.Record.SiteName = siteName;
|
||||
comment.Record.CommentText = commentText;
|
||||
comment.Record.Status = status;
|
||||
}
|
||||
|
||||
public void ApproveComment(int commentId) {
|
||||
Comment comment = GetComment(commentId);
|
||||
comment.Status = CommentStatus.Approved;
|
||||
comment.Record.Status = CommentStatus.Approved;
|
||||
}
|
||||
|
||||
public void PendComment(int commentId) {
|
||||
Comment comment = GetComment(commentId);
|
||||
comment.Status = CommentStatus.Pending;
|
||||
comment.Record.Status = CommentStatus.Pending;
|
||||
}
|
||||
|
||||
public void MarkCommentAsSpam(int commentId) {
|
||||
Comment comment = GetComment(commentId);
|
||||
comment.Status = CommentStatus.Spam;
|
||||
comment.Record.Status = CommentStatus.Spam;
|
||||
}
|
||||
|
||||
public void DeleteComment(int commentId) {
|
||||
_commentRepository.Delete(GetComment(commentId));
|
||||
_contentManager.Remove(_contentManager.Get(commentId));
|
||||
}
|
||||
|
||||
public bool CommentsClosedForCommentedContent(int id) {
|
||||
return _closedCommentsRepository.Get(x => x.ContentItemId == id) == null ? false : true;
|
||||
return _closedCommentsRepository.Fetch(x => x.ContentItemId == id).Count() >= 1;
|
||||
}
|
||||
|
||||
public void CloseCommentsForCommentedContent(int id) {
|
||||
_closedCommentsRepository.Create(new ClosedComments { ContentItemId = id });
|
||||
if (CommentsClosedForCommentedContent(id))
|
||||
return;
|
||||
_closedCommentsRepository.Create(new ClosedCommentsRecord { ContentItemId = id });
|
||||
}
|
||||
|
||||
public void EnableCommentsForCommentedContent(int id) {
|
||||
ClosedComments closedComments = _closedCommentsRepository.Get(x => x.ContentItemId == id);
|
||||
if (closedComments != null) {
|
||||
_closedCommentsRepository.Delete(closedComments);
|
||||
}
|
||||
var closedComments = _closedCommentsRepository.Fetch(x => x.ContentItemId == id);
|
||||
closedComments.ForEach(c => _closedCommentsRepository.Delete(c));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Orchard.Comments.Services {
|
||||
|
||||
#region Implementation of ICommentValidator
|
||||
|
||||
public bool ValidateComment(Comment comment) {
|
||||
public bool ValidateComment(CommentRecord comment) {
|
||||
CommentSettingsRecord commentSettingsRecord = CurrentSite.As<CommentSettings>().Record;
|
||||
string akismetKey = commentSettingsRecord.AkismetKey;
|
||||
string akismetUrl = commentSettingsRecord.AkismetUrl;
|
||||
|
||||
@@ -2,6 +2,6 @@ using Orchard.Comments.Models;
|
||||
|
||||
namespace Orchard.Comments.Services {
|
||||
public interface ICommentValidator : IDependency {
|
||||
bool ValidateComment(Comment comment);
|
||||
bool ValidateComment(CommentRecord comment);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@ using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Comments.ViewModels {
|
||||
public class CommentCountViewModel {
|
||||
public CommentCountViewModel() {
|
||||
}
|
||||
|
||||
public CommentCountViewModel(HasComments part) {
|
||||
Item = part.ContentItem;
|
||||
CommentCount = part.Comments.Count;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Orchard.Comments.ViewModels {
|
||||
}
|
||||
|
||||
public class CommentEntry {
|
||||
public Comment Comment { get; set; }
|
||||
public CommentRecord Comment { get; set; }
|
||||
public string CommentedOn { get; set; }
|
||||
public bool IsChecked { get; set; }
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<%=Html.Encode(commentEntry.Comment.CommentText.Length > 23 ? commentEntry.Comment.CommentText.Substring(0, 24) : commentEntry.Comment.CommentText) %><%=_Encoded(" ...") %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td><%=commentEntry.Comment.CommentDate.ToLocalTime() %></td>
|
||||
<td><%=commentEntry.Comment.CommentDateUtc.ToLocalTime() %></td>
|
||||
<td>
|
||||
<ul class="actions">
|
||||
<li class="construct">
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<%=Html.Encode(commentEntry.Comment.CommentText.Length > 23 ? commentEntry.Comment.CommentText.Substring(0, 24) : commentEntry.Comment.CommentText) %><%=_Encoded(" ...") %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td><%=commentEntry.Comment.CommentDate.ToLocalTime() %></td>
|
||||
<td><%=commentEntry.Comment.CommentDateUtc.ToLocalTime() %></td>
|
||||
<td><%=Html.ActionLink(commentEntry.CommentedOn, "Details", new { id = commentEntry.Comment.CommentedOn }) %></td>
|
||||
<td>
|
||||
<ul class="actions">
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
foreach (var comment in Model) { %>
|
||||
<li>
|
||||
<div class="comment">
|
||||
<span class="who"><%=Html.LinkOrDefault(Html.Encode(comment.UserName), Html.Encode(comment.SiteName), new { rel = "nofollow" })%></span>
|
||||
<span class="who"><%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%></span>
|
||||
<%-- todo: (heskew) need comment permalink --%>
|
||||
<span>said <%=Html.Link(Html.DateTimeRelative(comment.CommentDate), "#")%></span>
|
||||
<span>said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc), "#")%></span>
|
||||
</div>
|
||||
<div class="text">
|
||||
<%-- todo: (heskew) comment text needs processing depending on comment markup style --%>
|
||||
<p><%=Html.Encode(comment.CommentText) %></p>
|
||||
<p><%=Html.Encode(comment.Record.CommentText)%></p>
|
||||
</div>
|
||||
</li><%
|
||||
} %>
|
||||
|
||||
@@ -5,11 +5,11 @@ foreach (var comment in Model) { %>
|
||||
<li>
|
||||
|
||||
<div class="comment">
|
||||
<p><%=Html.Encode(comment.CommentText) %></p>
|
||||
<p><%=Html.Encode(comment.Record.CommentText) %></p>
|
||||
</div>
|
||||
|
||||
<div class="commentauthor">
|
||||
<span class="who"><%=Html.LinkOrDefault(Html.Encode(comment.UserName), Html.Encode(comment.SiteName), new { rel = "nofollow" })%></span> <span>said <%=Html.Link(Html.DateTimeRelative(comment.CommentDate), "#")%></span>
|
||||
<span class="who"><%=Html.LinkOrDefault(Html.Encode(comment.Record.UserName), Html.Encode(comment.Record.SiteName), new { rel = "nofollow" })%></span> <span>said <%=Html.Link(Html.DateTimeRelative(comment.Record.CommentDateUtc), "#")%></span>
|
||||
</div>
|
||||
|
||||
</li><%
|
||||
|
||||
@@ -2,6 +2,9 @@ using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.ContentManagement.Handlers {
|
||||
/// <summary>
|
||||
/// Filter reponsible for adding a part to a content item when content items are activated
|
||||
/// </summary>
|
||||
public class ActivatingFilter<TPart> : IContentActivatingFilter where TPart : ContentPart, new() {
|
||||
private readonly Func<string, bool> _predicate;
|
||||
|
||||
@@ -18,5 +21,4 @@ namespace Orchard.ContentManagement.Handlers {
|
||||
context.Builder.Weld<TPart>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace Orchard.ContentManagement.Handlers {
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
|
||||
protected override void Activated(ActivatedContentContext context, ContentPart<TRecord> instance) {
|
||||
instance.Record = new TRecord();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user