- 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:
suhacan
2009-11-19 21:58:48 +00:00
parent 4c9a241240
commit f29342735f
7 changed files with 326 additions and 1 deletions

View 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" }))
);
}
}
}

View File

@@ -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);
}
}
}
}

View 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
}
}

View File

@@ -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" />

View File

@@ -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
}
}

View File

@@ -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,
}
}

View File

@@ -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"); %>