mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Implementing comments notifications
This commit is contained in:
@@ -117,6 +117,13 @@ namespace Orchard.Comments.Controllers {
|
||||
else {
|
||||
Services.Notifier.Information(T("Your comment has been posted."));
|
||||
}
|
||||
|
||||
// send email notification
|
||||
var siteSettings = Services.WorkContext.CurrentSite.As<CommentSettingsPart>();
|
||||
if (siteSettings.NotificationEmail) {
|
||||
_commentService.SendNotificationEmail(commentPart);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
Services.TransactionManager.Cancel();
|
||||
|
@@ -13,5 +13,11 @@ namespace Orchard.Comments.Models {
|
||||
get { return this.Retrieve(x => x.ClosedCommentsDelay); }
|
||||
set { this.Store(x => x.ClosedCommentsDelay, value); }
|
||||
}
|
||||
|
||||
public bool NotificationEmail {
|
||||
get { return this.Retrieve(x => x.NotificationEmail); }
|
||||
set { this.Store(x => x.NotificationEmail, value); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -178,6 +178,9 @@
|
||||
<ItemGroup>
|
||||
<Content Include="Views\CommentText.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Template.Comment.Notification.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
@@ -2,16 +2,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using System.Xml.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Comments.Models;
|
||||
using Orchard.Comments.Settings;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Descriptor;
|
||||
using Orchard.Environment.State;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Messaging.Services;
|
||||
using Orchard.Mvc.Extensions;
|
||||
using Orchard.Security;
|
||||
using Orchard.Services;
|
||||
|
||||
@@ -25,6 +30,10 @@ namespace Orchard.Comments.Services {
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IShellDescriptorManager _shellDescriptorManager;
|
||||
private readonly HashSet<int> _processedCommentsParts = new HashSet<int>();
|
||||
private readonly IShapeFactory _shapeFactory;
|
||||
private readonly IShapeDisplay _shapeDisplay;
|
||||
private readonly IMessageService _messageService;
|
||||
private readonly IMembershipService _membershipService;
|
||||
|
||||
public CommentService(
|
||||
IOrchardServices orchardServices,
|
||||
@@ -32,16 +41,28 @@ namespace Orchard.Comments.Services {
|
||||
IEncryptionService encryptionService,
|
||||
IProcessingEngine processingEngine,
|
||||
ShellSettings shellSettings,
|
||||
IShellDescriptorManager shellDescriptorManager) {
|
||||
IShellDescriptorManager shellDescriptorManager,
|
||||
IShapeFactory shapeFactory,
|
||||
IShapeDisplay shapeDisplay,
|
||||
IMessageService messageService,
|
||||
IMembershipService membershipService
|
||||
) {
|
||||
_orchardServices = orchardServices;
|
||||
_clock = clock;
|
||||
_encryptionService = encryptionService;
|
||||
_processingEngine = processingEngine;
|
||||
_shellSettings = shellSettings;
|
||||
_shellDescriptorManager = shellDescriptorManager;
|
||||
_shapeFactory = shapeFactory;
|
||||
_shapeDisplay = shapeDisplay;
|
||||
_messageService = messageService;
|
||||
_membershipService = membershipService;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public CommentPart GetComment(int id) {
|
||||
@@ -196,6 +217,48 @@ namespace Orchard.Comments.Services {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SendNotificationEmail(CommentPart commentPart) {
|
||||
try {
|
||||
var commentedOn = _orchardServices.ContentManager.Get(commentPart.CommentedOn);
|
||||
if (commentedOn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var owner = commentedOn.As<CommonPart>().Owner;
|
||||
if (owner == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var template = _shapeFactory.Create("Template_Comment_Notification", Arguments.From(new {
|
||||
CommentPart = commentPart,
|
||||
CommentApproveUrl = CreateProtectedUrl("Approve", commentPart),
|
||||
CommentModerateUrl = CreateProtectedUrl("Moderate", commentPart),
|
||||
CommentDeleteUrl = CreateProtectedUrl("Delete", commentPart)
|
||||
}));
|
||||
|
||||
var parameters = new Dictionary<string, object> {
|
||||
{"Subject", T("Comment notification").Text},
|
||||
{"Body", _shapeDisplay.Display(template)},
|
||||
{"Recipients", owner.Email}
|
||||
};
|
||||
|
||||
_messageService.Send("Email", parameters);
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Error(e, "An unexpected error occured while sending a notification email");
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateProtectedUrl(string action, CommentPart part) {
|
||||
var workContext = _orchardServices.WorkContext;
|
||||
if (workContext.HttpContext != null) {
|
||||
var url = new UrlHelper(workContext.HttpContext.Request.RequestContext);
|
||||
return url.AbsoluteAction(action, "Comment", new { area = "Orchard.Comments", nonce = CreateNonce(part, TimeSpan.FromDays(7)) });
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CommentPart GetCommentWithQueryHints(int id) {
|
||||
return _orchardServices.ContentManager.Get<CommentPart>(id, VersionOptions.Latest, new QueryHints().ExpandParts<CommentPart>());
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ namespace Orchard.Comments.Services {
|
||||
string CreateNonce(CommentPart comment, TimeSpan delay);
|
||||
bool CanStillCommentOn(CommentsPart commentsPart);
|
||||
bool CanCreateComment(CommentPart commentPart);
|
||||
|
||||
void SendNotificationEmail(CommentPart commentPart);
|
||||
string CreateProtectedUrl(string action, CommentPart part);
|
||||
}
|
||||
}
|
@@ -4,22 +4,18 @@ using Orchard.Comments.Models;
|
||||
using Orchard.Comments.Services;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Mvc.Extensions;
|
||||
using Orchard.Tokens;
|
||||
|
||||
namespace Orchard.Comments.Tokens {
|
||||
|
||||
public class CommentTokens : ITokenProvider {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IWorkContextAccessor _workContextAccessor;
|
||||
private readonly ICommentService _commentService;
|
||||
|
||||
public CommentTokens(
|
||||
IContentManager contentManager,
|
||||
IWorkContextAccessor workContextAccessor,
|
||||
ICommentService commentService) {
|
||||
_contentManager = contentManager;
|
||||
_workContextAccessor = workContextAccessor;
|
||||
_commentService = commentService;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
@@ -51,22 +47,12 @@ namespace Orchard.Comments.Tokens {
|
||||
.Chain("CommentAuthorUrl", "Text", content => content.As<CommentPart>().SiteName)
|
||||
.Token("CommentAuthorEmail", content => content.As<CommentPart>().Email)
|
||||
.Chain("CommentAuthorEmail", "Text", content => content.As<CommentPart>().Email)
|
||||
.Token("CommentApproveUrl", content => CreateProtectedUrl("Approve", content.As<CommentPart>()))
|
||||
.Token("CommentModerateUrl", content => CreateProtectedUrl("Moderate", content.As<CommentPart>()))
|
||||
.Token("CommentDeleteUrl", content => CreateProtectedUrl("Delete", content.As<CommentPart>()))
|
||||
.Token("CommentApproveUrl", content => _commentService.CreateProtectedUrl("Approve", content.As<CommentPart>()))
|
||||
.Token("CommentModerateUrl", content => _commentService.CreateProtectedUrl("Moderate", content.As<CommentPart>()))
|
||||
.Token("CommentDeleteUrl", content => _commentService.CreateProtectedUrl("Delete", content.As<CommentPart>()))
|
||||
;
|
||||
}
|
||||
|
||||
private string CreateProtectedUrl(string action, CommentPart part) {
|
||||
var workContext = _workContextAccessor.GetContext();
|
||||
if (workContext.HttpContext != null) {
|
||||
var url = new UrlHelper(workContext.HttpContext.Request.RequestContext);
|
||||
return url.AbsoluteAction(action, "Comment", new {area = "Orchard.Comments", nonce = _commentService.CreateNonce(part, TimeSpan.FromDays(7))});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string CommentAuthor(IContent comment) {
|
||||
var commentPart = comment.As<CommentPart>();
|
||||
return String.IsNullOrWhiteSpace(commentPart.UserName) ? commentPart.Author : commentPart.UserName;
|
||||
|
@@ -1,4 +1,11 @@
|
||||
@model Orchard.Comments.Models.CommentSettingsPart
|
||||
@using Orchard.Messaging.Services;
|
||||
|
||||
@{
|
||||
var messageManager = WorkContext.Resolve<IMessageManager>();
|
||||
var emailEnabled = messageManager.GetAvailableChannelServices().Contains("email");
|
||||
}
|
||||
|
||||
|
||||
<fieldset>
|
||||
<legend>@T("Comments")</legend>
|
||||
@@ -16,4 +23,15 @@
|
||||
<span class="hint">@T("Number of days after comments are automatically closed. Leave to 0 to have them always available.")</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="checkbox" value="true" class="check-box" id="@Html.FieldIdFor(m => m.NotificationEmail)" name="@Html.FieldNameFor(m => m.NotificationEmail)" @(emailEnabled ? "" : "disabled=\"disabled\"") />
|
||||
<label class="forcheckbox" for="CommentSettings_NotificationEmail">@T("Notification email")</label>
|
||||
@Html.ValidationMessage("NotificationEmail", "*")
|
||||
<span class="hint">@T("Check to send comment notification emails to the commented content author at their account’s email address.")</span>
|
||||
|
||||
@if (!emailEnabled) {
|
||||
<div class="message message-Warning">@T("This option is available when an email module is activated.")</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</fieldset>
|
@@ -0,0 +1,24 @@
|
||||
@using Orchard.Comments.Models;
|
||||
|
||||
@{
|
||||
CommentPart commentPart = Model.CommentPart;
|
||||
string approveUrl = Model.CommentApproveUrl;
|
||||
string moderateUrl = Model.CommentModerateUrl;
|
||||
string deleteUrl = Model.CommentDeleteUrl;
|
||||
}
|
||||
<br />
|
||||
|
||||
@T("A new comment is available.") <br />
|
||||
@T("From: {0}", commentPart.UserName) <br/>
|
||||
@T("Site: {0}", commentPart.SiteName) <br />
|
||||
@T("Email: {0}", commentPart.Email) <br />
|
||||
@T("Comment: {0}", commentPart.CommentText) <br />
|
||||
|
||||
@if (commentPart.Status == CommentStatus.Pending) {
|
||||
@T("The comment is moderated. <a href=\"{0}\">Approve</a> ", approveUrl)
|
||||
}
|
||||
@if (commentPart.Status == CommentStatus.Approved) {
|
||||
@T("The comment is public. <a href=\"{0}\">Unapprove</a> ", moderateUrl)
|
||||
}
|
||||
@T("<a href=\"{0}\">Delete</a> ", deleteUrl)
|
||||
|
Reference in New Issue
Block a user