mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-20 02:37:55 +08:00
- Comments: comment management, bulk delete/mark as spam, filtering (spam/approved/all)...
--HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4041452
This commit is contained in:
14
src/Orchard.Web/Packages/Orchard.Comments/AdminMenu.cs
Normal file
14
src/Orchard.Web/Packages/Orchard.Comments/AdminMenu.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Orchard.UI.Navigation;
|
||||||
|
|
||||||
|
namespace Orchard.Comments {
|
||||||
|
public class AdminMenu : INavigationProvider {
|
||||||
|
public string MenuName { get { return "admin"; } }
|
||||||
|
|
||||||
|
public void GetNavigation(NavigationBuilder builder) {
|
||||||
|
builder.Add("Comments", "3",
|
||||||
|
menu => menu
|
||||||
|
.Add("Manage Comments", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Comments" }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,127 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using Orchard.Comments.Models;
|
||||||
|
using Orchard.Localization;
|
||||||
|
using Orchard.Logging;
|
||||||
|
using Orchard.UI.Notify;
|
||||||
|
using Orchard.Security;
|
||||||
|
using Orchard.Comments.ViewModels;
|
||||||
|
using Orchard.Comments.Services;
|
||||||
|
|
||||||
|
namespace Orchard.Comments.Controllers {
|
||||||
|
[ValidateInput(false)]
|
||||||
|
public class AdminController : Controller {
|
||||||
|
private readonly ICommentService _commentService;
|
||||||
|
private readonly IAuthorizer _authorizer;
|
||||||
|
private readonly INotifier _notifier;
|
||||||
|
|
||||||
|
public AdminController(ICommentService commentService, INotifier notifier, IAuthorizer authorizer) {
|
||||||
|
_commentService = commentService;
|
||||||
|
_authorizer = authorizer;
|
||||||
|
_notifier = notifier;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
T = NullLocalizer.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUser CurrentUser { get; set; }
|
||||||
|
public ISite CurrentSite { get; set; }
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
|
public ActionResult Index(CommentIndexOptions options) {
|
||||||
|
// Default options
|
||||||
|
if (options == null)
|
||||||
|
options = new CommentIndexOptions();
|
||||||
|
|
||||||
|
// Filtering
|
||||||
|
IEnumerable<Comment> comments;
|
||||||
|
try {
|
||||||
|
switch (options.Filter) {
|
||||||
|
case CommentIndexFilter.All:
|
||||||
|
comments = _commentService.GetComments();
|
||||||
|
break;
|
||||||
|
case CommentIndexFilter.Approved:
|
||||||
|
comments = _commentService.GetComments(CommentStatus.Approved);
|
||||||
|
break;
|
||||||
|
case CommentIndexFilter.Spam:
|
||||||
|
comments = _commentService.GetComments(CommentStatus.Spam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
var entries = comments.Select(comment => CreateCommentEntry(comment)).ToList();
|
||||||
|
var model = new CommentsIndexViewModel {Comments = entries, Options = options};
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
catch (Exception exception) {
|
||||||
|
_notifier.Error(T("Listing comments failed: " + exception.Message));
|
||||||
|
return Index(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[FormValueRequired("submit.BulkEdit")]
|
||||||
|
public ActionResult Index(FormCollection input) {
|
||||||
|
var viewModel = new CommentsIndexViewModel { Comments = new List<CommentEntry>(), Options = new CommentIndexOptions() };
|
||||||
|
UpdateModel(viewModel, input.ToValueProvider());
|
||||||
|
|
||||||
|
try {
|
||||||
|
IEnumerable<CommentEntry> checkedEntries = viewModel.Comments.Where(c => c.IsChecked);
|
||||||
|
switch (viewModel.Options.BulkAction) {
|
||||||
|
case CommentIndexBulkAction.None:
|
||||||
|
break;
|
||||||
|
case CommentIndexBulkAction.MarkAsSpam:
|
||||||
|
if (!_authorizer.Authorize(Permissions.ModerateComment, T("Couldn't moderate comment")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
//TODO: Transaction
|
||||||
|
foreach (CommentEntry entry in checkedEntries) {
|
||||||
|
_commentService.MarkCommentAsSpam(entry.Comment.Id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CommentIndexBulkAction.Delete:
|
||||||
|
if (!_authorizer.Authorize(Permissions.ModerateComment, T("Couldn't delete comment")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
foreach (CommentEntry entry in checkedEntries) {
|
||||||
|
_commentService.DeleteComment(entry.Comment.Id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception) {
|
||||||
|
_notifier.Error(T("Editing comments failed: " + exception.Message));
|
||||||
|
return Index(viewModel.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CommentEntry CreateCommentEntry(Comment comment) {
|
||||||
|
return new CommentEntry {
|
||||||
|
Comment = comment,
|
||||||
|
IsChecked = false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
|
||||||
|
private readonly string _submitButtonName;
|
||||||
|
|
||||||
|
public FormValueRequiredAttribute(string submitButtonName) {
|
||||||
|
_submitButtonName = submitButtonName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
|
||||||
|
var value = controllerContext.HttpContext.Request.Form[_submitButtonName];
|
||||||
|
return !string.IsNullOrEmpty(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/Orchard.Web/Packages/Orchard.Comments/Models/Comment.cs
Normal file
17
src/Orchard.Web/Packages/Orchard.Comments/Models/Comment.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Orchard.Comments.Models {
|
||||||
|
public class Comment {
|
||||||
|
public virtual int Id { get; set; }
|
||||||
|
public virtual string Author { 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 enum CommentStatus {
|
||||||
|
Approved,
|
||||||
|
Spam
|
||||||
|
}
|
||||||
|
}
|
@@ -61,12 +61,18 @@
|
|||||||
<Reference Include="System.Web.Mobile" />
|
<Reference Include="System.Web.Mobile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="AdminMenu.cs" />
|
||||||
|
<Compile Include="Controllers\AdminController.cs" />
|
||||||
|
<Compile Include="Models\Comment.cs" />
|
||||||
<Compile Include="Models\CommentSettings.cs" />
|
<Compile Include="Models\CommentSettings.cs" />
|
||||||
<Compile Include="Permissions.cs" />
|
<Compile Include="Permissions.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Services\CommentService.cs" />
|
||||||
|
<Compile Include="ViewModels\CommentsIndexViewModel.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Package.txt" />
|
<Content Include="Package.txt" />
|
||||||
|
<Content Include="Views\Admin\Index.aspx" />
|
||||||
<Content Include="Views\Models\EditorTemplates\CommentSettingsRecord.ascx" />
|
<Content Include="Views\Models\EditorTemplates\CommentSettingsRecord.ascx" />
|
||||||
<Content Include="Web.config" />
|
<Content Include="Web.config" />
|
||||||
<Content Include="Views\Web.config" />
|
<Content Include="Views\Web.config" />
|
||||||
@@ -80,7 +86,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="App_Data\" />
|
<Folder Include="App_Data\" />
|
||||||
<Folder Include="Content\" />
|
<Folder Include="Content\" />
|
||||||
<Folder Include="Controllers\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||||
|
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.Comments.Models;
|
||||||
|
using Orchard.Data;
|
||||||
|
using Orchard.Logging;
|
||||||
|
|
||||||
|
namespace Orchard.Comments.Services {
|
||||||
|
public interface ICommentService : IDependency {
|
||||||
|
IEnumerable<Comment> GetComments();
|
||||||
|
IEnumerable<Comment> GetComments(CommentStatus status);
|
||||||
|
Comment GetComment(int id);
|
||||||
|
void MarkCommentAsSpam(int commentId);
|
||||||
|
void DeleteComment(int commentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommentService : ICommentService {
|
||||||
|
private readonly IRepository<Comment> _commentRepository;
|
||||||
|
|
||||||
|
public CommentService(IRepository<Comment> commentRepository) {
|
||||||
|
_commentRepository = commentRepository;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
#region Implementation of ICommentService
|
||||||
|
|
||||||
|
public IEnumerable<Comment> GetComments() {
|
||||||
|
return from comment in _commentRepository.Table.ToList() select comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Comment> GetComments(CommentStatus status) {
|
||||||
|
return from comment in _commentRepository.Table.ToList() where comment.Status == CommentStatus.Approved select comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Comment GetComment(int id) {
|
||||||
|
return _commentRepository.Get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkCommentAsSpam(int commentId) {
|
||||||
|
Comment comment = GetComment(commentId);
|
||||||
|
comment.Status = CommentStatus.Spam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteComment(int commentId) {
|
||||||
|
_commentRepository.Delete(GetComment(commentId));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.Comments.Models;
|
||||||
|
using Orchard.Mvc.ViewModels;
|
||||||
|
|
||||||
|
namespace Orchard.Comments.ViewModels {
|
||||||
|
public class CommentsIndexViewModel : AdminViewModel {
|
||||||
|
public IList<CommentEntry> Comments { get; set; }
|
||||||
|
public CommentIndexOptions Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommentEntry {
|
||||||
|
public Comment Comment { get; set; }
|
||||||
|
public bool IsChecked { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommentIndexOptions {
|
||||||
|
public CommentIndexFilter Filter { get; set; }
|
||||||
|
public CommentIndexBulkAction BulkAction { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CommentIndexBulkAction {
|
||||||
|
None,
|
||||||
|
Delete,
|
||||||
|
MarkAsSpam,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CommentIndexFilter {
|
||||||
|
All,
|
||||||
|
Approved,
|
||||||
|
Spam,
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,78 @@
|
|||||||
|
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<CommentsIndexViewModel>" %>
|
||||||
|
<%@ Import Namespace="Orchard.Comments.Models"%>
|
||||||
|
<%@ Import Namespace="Orchard.Comments.ViewModels"%>
|
||||||
|
<%@ Import Namespace="Orchard.Mvc.Html"%>
|
||||||
|
<% Html.Include("Header"); %>
|
||||||
|
<% Html.BeginForm(); %>
|
||||||
|
<div class="yui-g">
|
||||||
|
<h2 class="separator">Manage Comments</h2>
|
||||||
|
<%=Html.ValidationSummary() %>
|
||||||
|
<ol class="horizontal actions floatLeft">
|
||||||
|
<li>
|
||||||
|
<label class="floatLeft" for="publishActions"> Actions:</label>
|
||||||
|
<select id="publishActions" name="<%=Html.NameOf(m => m.Options.BulkAction)%>">
|
||||||
|
<%=Html.SelectOption(Model.Options.BulkAction, CommentIndexBulkAction.None, "Choose action...")%>
|
||||||
|
<%=Html.SelectOption(Model.Options.BulkAction, CommentIndexBulkAction.Delete, "Delete")%>
|
||||||
|
<%=Html.SelectOption(Model.Options.BulkAction, CommentIndexBulkAction.MarkAsSpam, "Mark as Spam")%>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="button roundCorners" type="submit" name="submit.BulkEdit" value="Apply" />
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<ol class="horizontal actions">
|
||||||
|
<li>
|
||||||
|
<label class="floatLeft" for="filterResults"></label>
|
||||||
|
<select id="filterResults" name="<%=Html.NameOf(m => m.Options.Filter)%>">
|
||||||
|
<%=Html.SelectOption(Model.Options.Filter, CommentIndexFilter.All, "All Comments")%>
|
||||||
|
<%=Html.SelectOption(Model.Options.Filter, CommentIndexFilter.Approved, "Approved Comments")%>
|
||||||
|
<%=Html.SelectOption(Model.Options.Filter, CommentIndexFilter.Spam, "Spam")%>
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input class="button roundCorners" type="submit" name="submit.Filter" value="Filter"/>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<table id="Table1" cellspacing="0" class="roundCorners clearLayout" summary="This is a table of the comments in your application">
|
||||||
|
<colgroup>
|
||||||
|
<col id="Col1" />
|
||||||
|
<col id="Col2" />
|
||||||
|
<col id="Col3" />
|
||||||
|
<col id="Col4" />
|
||||||
|
<col id="Col5" />
|
||||||
|
<col id="Col6" />
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"><%--<input type="checkbox" value="" />--%></th>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<th scope="col">Author</th>
|
||||||
|
<th scope="col">Comment</th>
|
||||||
|
<th scope="col">Date</th>
|
||||||
|
<th scope="col">Commented On</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<%
|
||||||
|
int commentIndex = 0;
|
||||||
|
foreach (var commentEntry in Model.Comments) {
|
||||||
|
%>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<input type="hidden" value="<%=Model.Comments[commentIndex].Comment.Id%>" name="<%=Html.NameOf(m => m.Comments[commentIndex].Comment.Id)%>"/>
|
||||||
|
<input type="checkbox" value="true" name="<%=Html.NameOf(m => m.Comments[commentIndex].IsChecked)%>"/>
|
||||||
|
</td>
|
||||||
|
<td><% if (commentEntry.Comment.Status == CommentStatus.Spam) {%> Spam <% } %>
|
||||||
|
<% else {%> Approved <% } %>
|
||||||
|
</td>
|
||||||
|
<td><%= commentEntry.Comment.Author %></td>
|
||||||
|
<td><%= commentEntry.Comment.CommentText.Substring(32) %></td>
|
||||||
|
<td><%= commentEntry.Comment.CommentDate %></td>
|
||||||
|
<td>Link to commented item</td>
|
||||||
|
</tr>
|
||||||
|
<%
|
||||||
|
commentIndex++;
|
||||||
|
} %>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% Html.EndForm(); %>
|
||||||
|
<% Html.Include("Footer"); %>
|
Reference in New Issue
Block a user