public void Create_WithFeedbackItem_SetsDateCreatedAndModifiedToUtcNow() { // Arrange var now = DateTime.UtcNow; var sps = new Mock<StoredProcedures>("test"); sps.Setup(s => s.InsertFeedback(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int?>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), It.IsAny<DateTime?>(), It.IsAny<DateTime>())); var repository = new DatabaseObjectProvider(blogId: 1, procedures: sps.Object); var feedback = new FeedbackItem(FeedbackType.Comment) { Body = "blah" }; // Act repository.Create(feedback); // Assert Assert.GreaterEqualThan(DateTime.UtcNow, feedback.DateCreatedUtc); Assert.GreaterEqualThan(DateTime.UtcNow, feedback.DateModifiedUtc); Assert.GreaterEqualThan(feedback.DateCreatedUtc, now); Assert.GreaterEqualThan(feedback.DateModifiedUtc, now); }
public void CreateSetsDateCreated() { //arrange var blog = new Mock<Blog>(); DateTime dateCreatedUtc = DateTime.UtcNow; blog.Object.Id = 1; var entry = new Entry(PostType.BlogPost, blog.Object) { Id = 123, BlogId = 1, CommentingClosed = false }; var repository = new Mock<ObjectRepository>(); repository.Setup(r => r.GetEntry(It.IsAny<int>(), true, true)).Returns(entry); var context = new Mock<ISubtextContext>(); context.SetupGet(c => c.Repository).Returns(repository.Object); context.SetupGet(c => c.Blog).Returns(blog.Object); context.SetupGet(c => c.HttpContext.Items).Returns(new Hashtable()); context.SetupGet(c => c.Cache).Returns(new TestCache()); var service = new CommentService(context.Object, null); var comment = new FeedbackItem(FeedbackType.Comment) { EntryId = 123, BlogId = 1, Body = "test", Title = "title" }; //act service.Create(comment, true/*runFilters*/); //assert Assert.GreaterEqualThan(comment.DateCreatedUtc, dateCreatedUtc); Assert.GreaterEqualThan(DateTime.UtcNow, comment.DateCreatedUtc); }
/// <summary> /// Filters the comment. Throws an exception should the comment not be allowed. /// Otherwise returns true. This interface may be changed. /// </summary> /// <remarks> /// <p> /// The first filter examines whether comments are coming in too quickly /// from the same SourceUrl. Looks at the <see cref="BlogInfo.CommentDelayInMinutes"/>. /// </p> /// <p> /// The second filter checks for duplicate comments. It only looks at the body /// of the comment. /// </p> /// </remarks> /// <param name="feedbackItem">Entry.</param> public void FilterAfterPersist(FeedbackItem feedbackItem) { if (!SecurityHelper.IsAdmin) { if (!Config.CurrentBlog.ModerationEnabled) { //Akismet Check... if (Config.CurrentBlog.FeedbackSpamServiceEnabled) { if (Config.CurrentBlog.FeedbackSpamService.IsSpam(feedbackItem)) { FlagAsSpam(feedbackItem); return; } } //Note, we need to explicitely set the status flag here. //Just setting Approved = true would not reset any other bits in the flag that may be set. feedbackItem.Status = FeedbackStatusFlag.Approved; } else //Moderated! { //Note, we need to explicitely set the status flag here. //Just setting NeedsModeration = true would not reset any other bits in the flag that may be set. feedbackItem.Status = FeedbackStatusFlag.NeedsModeration; } } else { //Note, we need to explicitely set the status flag here. //Just setting Approved = true would not reset any other bits in the flag that may be set. feedbackItem.Status = FeedbackStatusFlag.Approved; } FeedbackItem.Update(feedbackItem); }
public void CreateDoesNotChangeDateCreatedAndDateModifiedIfAlreadySpecified() { //arrange var blog = new Mock<Blog>(); DateTime dateCreated = DateTime.Now; blog.Object.Id = 1; blog.Setup(b => b.TimeZone.Now).Returns(dateCreated); var entry = new Entry(PostType.BlogPost, blog.Object) {Id = 123, BlogId = 1, CommentingClosed = false}; var repository = new Mock<ObjectProvider>(); repository.Setup(r => r.GetEntry(It.IsAny<int>(), true, true)).Returns(entry); var context = new Mock<ISubtextContext>(); context.SetupGet(c => c.Repository).Returns(repository.Object); context.SetupGet(c => c.Blog).Returns(blog.Object); context.SetupGet(c => c.HttpContext.Items).Returns(new Hashtable()); context.SetupGet(c => c.Cache).Returns(new TestCache()); var service = new CommentService(context.Object, null); var comment = new FeedbackItem(FeedbackType.Comment) { EntryId = 123, BlogId = 1, Body = "test", Title = "title", DateCreated = dateCreated.AddDays(-2), DateModified = dateCreated.AddDays(-1) }; //act service.Create(comment, true/*runFilters*/); //assert Assert.AreEqual(dateCreated.AddDays(-2), comment.DateCreated); Assert.AreEqual(dateCreated.AddDays(-1), comment.DateModified); }
public override int Create(FeedbackItem feedbackItem) { if (feedbackItem == null) throw new ArgumentNullException("feedbackItem"); string ipAddress = null; if (feedbackItem.IpAddress != null) ipAddress = feedbackItem.IpAddress.ToString(); string sourceUrl = null; if (feedbackItem.SourceUrl != null) sourceUrl = feedbackItem.SourceUrl.ToString(); return _procedures.InsertFeedback(feedbackItem.Title, feedbackItem.Body, BlogId, feedbackItem.EntryId.NullIfMinValue(), feedbackItem.Author, feedbackItem.IsBlogAuthor, feedbackItem.Email, sourceUrl, (int)feedbackItem.FeedbackType, (int)feedbackItem.Status, feedbackItem.CreatedViaCommentApi, feedbackItem.Referrer, ipAddress, feedbackItem.UserAgent, feedbackItem.ChecksumHash, feedbackItem.DateCreated, feedbackItem.DateModified, CurrentDateTime); }
/// <summary> /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"></see> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpContext"></see> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param> public void ProcessRequest(HttpContext context) { HttpRequest Request = context.Request; if(Request.RequestType == "POST" && Request.ContentType == "text/xml") { XmlDocument doc = new XmlDocument(); doc.Load(Request.InputStream); FeedbackItem comment = new FeedbackItem(FeedbackType.Comment); comment.CreatedViaCommentAPI = true; string name = doc.SelectSingleNode("//item/author").InnerText; if(name.IndexOf("<") != -1) { name = name.Substring(0, name.IndexOf("<")); } comment.Author = name.Trim(); comment.Body = doc.SelectSingleNode("//item/description").InnerText; comment.Title = doc.SelectSingleNode("//item/title").InnerText; comment.SourceUrl = HtmlHelper.CheckForUrl(doc.SelectSingleNode("//item/link").InnerText); comment.EntryId = UrlFormats.GetPostIDFromUrl(Request.Path); // [ 1644691 ] Closing comments didn't stop the CommentAPI if(!Subtext.Framework.Data.Cacher.GetEntry(comment.EntryId,CacheDuration.Medium).CommentingClosed) FeedbackItem.Create(comment, new CommentFilter(HttpContext.Current.Cache)); } }
public void EmailCommentToBlogAuthor_WithBlog_UsesBlogEmailForToEmail() { //arrange var comment = new FeedbackItem(FeedbackType.Comment) {Id = 121, Author = "me", Title = "the subject", FlaggedAsSpam = false}; var emailProvider = new Mock<EmailProvider>(); var templateEngine = new Mock<ITemplateEngine>(); var template = new Mock<ITextTemplate>(); templateEngine.Setup(t => t.GetTemplate(It.IsAny<string>())).Returns(template.Object); template.Setup(t => t.Format(It.IsAny<object>())).Returns("message"); var urlHelper = new Mock<BlogUrlHelper>(); urlHelper.Setup(u => u.FeedbackUrl(comment)).Returns("/"); var context = new Mock<ISubtextContext>(); context.Setup(c => c.UrlHelper).Returns(urlHelper.Object); context.Setup(c => c.Blog).Returns(new Blog {Email = "*****@*****.**", Author = "to", Host = "localhost", Title = "the blog"}); string toEmail = null; emailProvider.Setup( e => e.Send(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Callback <string, string, string, string>((to, from, title, message) => toEmail = to); var emailService = new EmailService(emailProvider.Object, templateEngine.Object, context.Object); //act emailService.EmailCommentToBlogAuthor(comment); //assert Assert.AreEqual("*****@*****.**", toEmail); }
public void FeedbackCreateCallsCommentService(bool isSpam, bool isAdmin) { Assert.IsTrue(Config.CreateBlog("", "username", "password", _hostName, string.Empty)); MockRepository mocks = new MockRepository(); IFeedbackSpamService service = (IFeedbackSpamService)mocks.CreateMock(typeof(IFeedbackSpamService)); Config.CurrentBlog.FeedbackSpamService = service; Config.CurrentBlog.DuplicateCommentsEnabled = true; Config.CurrentBlog.FeedbackSpamServiceKey = "my-secret-key"; Config.CurrentBlog.ModerationEnabled = false; FeedbackItem feedback = new FeedbackItem(FeedbackType.Comment); Expect.Call(service.IsSpam(feedback)).Return(isSpam); feedback.Title = "blah"; feedback.Body = UnitTestHelper.GenerateRandomString(); mocks.ReplayAll(); Assert.AreEqual(isAdmin, SecurityHelper.IsAdmin); try { FeedbackItem.Create(feedback, new CommentFilter(new Cache())); } catch(BaseCommentException) { } Assert.AreEqual(!isSpam, feedback.Approved); }
public int Create(FeedbackItem comment, bool runFilters) { Entry entry = Cacher.GetEntry(comment.EntryId, SubtextContext); if(entry != null && entry.CommentingClosed) { return NullValue.NullInt32; } ISubtextContext context = SubtextContext; HttpContextBase httpContext = context.HttpContext; if(httpContext != null && httpContext.Request != null) { comment.UserAgent = httpContext.Request.UserAgent; comment.IpAddress = HttpHelper.GetUserIpAddress(httpContext); } if(runFilters) { comment.FlaggedAsSpam = true; //We're going to start with this assumption. } comment.Author = HtmlHelper.SafeFormat(comment.Author, context.HttpContext.Server); comment.Body = HtmlHelper.ConvertUrlsToHyperLinks(HtmlHelper.ConvertToAllowedHtml(comment.Body)); comment.Title = HtmlHelper.SafeFormat(comment.Title, context.HttpContext.Server); // If we are creating this feedback item as part of an import, we want to // be sure to use the item's datetime, and not set it to the current time. if(NullValue.NullDateTime.Equals(comment.DateCreated)) { comment.DateCreated = context.Blog.TimeZone.Now; comment.DateModified = comment.DateCreated; } else if(NullValue.NullDateTime.Equals(comment.DateModified)) { comment.DateModified = comment.DateCreated; } comment.Entry = entry; if(runFilters) { OnBeforeCreate(comment); } comment.Id = Repository.Create(comment); if(runFilters) { OnAfterCreate(comment); } return comment.Id; }
/// <summary> /// Confirms the feedback as spam and moves it to the trash. /// </summary> /// <param name="feedback">The feedback.</param> public static void Delete(this ObjectRepository repository, FeedbackItem feedback) { if (feedback == null) { throw new ArgumentNullException("feedback"); } feedback.SetStatus(FeedbackStatusFlag.Approved, false); feedback.SetStatus(FeedbackStatusFlag.Deleted, true); repository.Update(feedback); }
public void EmailCommentToBlogAuthor_WithAuthor_SetsAuthorName() { //arrange var comment = new FeedbackItem(FeedbackType.Comment) {Id = 121, Author = "me", Title = "subject", Email = null}; string sentMessage = null; EmailService emailService = SetupEmailService(comment, "{comment.author}", sent => sentMessage = sent); //act emailService.EmailCommentToBlogAuthor(comment); //assert Assert.AreEqual("me", sentMessage); }
public void CannotCreateDuplicateComments() { Assert.IsTrue(Config.CreateBlog("", "username", "password", _hostName, string.Empty)); BlogInfo blog = Config.CurrentBlog; blog.CommentDelayInMinutes = 0; FeedbackItem feedbackItem = new FeedbackItem(FeedbackType.Comment); feedbackItem.DateCreated = DateTime.Now; feedbackItem.SourceUrl = new Uri("http://localhost/ThisUrl/"); feedbackItem.Title = "Some Title"; feedbackItem.Body = "Some Body"; FeedbackItem.Create(feedbackItem, new CommentFilter(HttpContext.Current.Cache)); FeedbackItem.Create(feedbackItem, new CommentFilter(HttpContext.Current.Cache)); }
public void EmailCommentToBlogAuthor(FeedbackItem comment) { if(String.IsNullOrEmpty(Blog.Email) || comment.FeedbackType == FeedbackType.PingTrack || Context.User.IsAdministrator()) { return; } string fromEmail = comment.Email; if(String.IsNullOrEmpty(fromEmail)) { fromEmail = null; } var commentForTemplate = new { blog = Blog, comment = new { author = comment.Author, title = comment.Title, source = Url.FeedbackUrl(comment).ToFullyQualifiedUrl(Blog), email = fromEmail ?? "none given", authorUrl = comment.SourceUrl, ip = comment.IpAddress, // we're sending plain text email by default, but body includes <br />s for crlf body = (comment.Body ?? string.Empty).Replace("<br />", Environment.NewLine).Replace("<br />", Environment. NewLine) }, spamFlag = comment.FlaggedAsSpam ? "Spam Flagged " : "" }; ITextTemplate template = TemplateEngine.GetTemplate("CommentReceived"); string message = template.Format(commentForTemplate); string subject = String.Format(CultureInfo.InvariantCulture, Resources.Email_CommentVia, comment.Title, Blog.Title); if(comment.FlaggedAsSpam) { subject = "[SPAM Flagged] " + subject; } string from = EmailProvider.UseCommentersEmailAsFromAddress ? (fromEmail ?? EmailProvider.AdminEmail) : EmailProvider.AdminEmail; EmailProvider.Send(Blog.Email, from, subject, message); }
public void ConvertToAkismetItem_WithContactPageFeedback_DoesNotSetPermalink() { // arrange var feedback = new FeedbackItem(FeedbackType.ContactPage); var urlHelper = new Mock<BlogUrlHelper>(); urlHelper.Setup(helper => helper.FeedbackUrl(It.IsAny<FeedbackItem>())).Returns((VirtualPath)null); urlHelper.Setup(helper => helper.BlogUrl()).Returns("/"); var service = new AkismetSpamService("abracadabra", new Blog {Host = "localhost"}, null, urlHelper.Object); // act var comment = service.ConvertToAkismetItem(feedback); // assert Assert.IsNull(comment.Permalink); }
/// <summary> /// Approves the comment, and removes it from the SPAM folder or from the /// Trash folder. /// </summary> /// <param name="feedback"></param> /// <param name="spamService"></param> /// <returns></returns> public static void Approve(this ObjectRepository repository, FeedbackItem feedback, ICommentSpamService spamService) { if (feedback == null) { throw new ArgumentNullException("feedback"); } feedback.SetStatus(FeedbackStatusFlag.Approved, true); feedback.SetStatus(FeedbackStatusFlag.Deleted, false); if (spamService != null) { spamService.SubmitGoodFeedback(feedback); } repository.Update(feedback); }
public void EmailCommentToBlogAuthor_WithBlogHavingNullEmail_DoesNotSendEmail() { //arrange var comment = new FeedbackItem(FeedbackType.Comment) {}; var blog = new Blog {Email = string.Empty}; var emailProvider = new Mock<EmailProvider>(); var context = new Mock<ISubtextContext>(); context.Setup(c => c.UrlHelper).Returns(new Mock<BlogUrlHelper>().Object); context.Setup(c => c.Blog).Returns(blog); var emailService = new EmailService(emailProvider.Object, new Mock<ITemplateEngine>().Object, context.Object); emailProvider.Setup( e => e.Send(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Throws( new Exception()); //act emailService.EmailCommentToBlogAuthor(comment); }
public void ConvertComment_WithDateCreated_ConvertsToUtc() { // arrange DateTime dateCreatedUtc = DateTime.ParseExact("2009/08/15 11:00 PM", "yyyy/MM/dd hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal).ToUniversalTime(); var feedback = new FeedbackItem(FeedbackType.Comment) { DateCreatedUtc = dateCreatedUtc, }; var subtextContext = new Mock<ISubtextContext>(); var converter = new BlogMLExportMapper(subtextContext.Object); // act var comment = converter.ConvertComment(feedback); // assert Assert.AreEqual(dateCreatedUtc, comment.DateCreated); }
public FeedbackAuthorViewModel(FeedbackItem comment) { IpAddress = comment.IpAddress; Name = HttpUtility.HtmlEncode(comment.Author); Url = HttpUtility.HtmlEncode(comment.SourceUrl); if (!string.IsNullOrEmpty(Url)) { SetUrlLink(); } if (!string.IsNullOrEmpty(comment.Email) && comment.Email.IndexOf("@") > 0) { Email = HttpUtility.HtmlEncode(comment.Email); FormattedEmail = "<" + Email + ">"; SetMailTo(comment); } }
public void Delete_WithEntryId_CallsDeleteEntryOnRepository() { // arrange var feedback = new FeedbackItem(FeedbackType.Comment) { Id = 123, Author = "Bugs" }; var service = new Mock<ICommentService>(); service.Setup(s => s.Get(123)).Returns(feedback); service.Setup(s => s.UpdateStatus(feedback, FeedbackStatusFlag.Deleted)); var controller = new CommentController(service.Object); // act var result = controller.UpdateStatus(123, FeedbackStatusFlag.Deleted) as JsonResult; // assert service.Verify(c => c.UpdateStatus(feedback, FeedbackStatusFlag.Deleted)); var data = new RouteValueDictionary(result.Data); Assert.AreEqual("Comment by Bugs", data["subject"]); Assert.AreEqual("has been removed", data["predicate"]); }
public void Destroy_WithEntryId_CallsDestroyFeedbackOnRepository() { // arrange var feedback = new FeedbackItem(FeedbackType.Comment) { Id = 123, Author = "Calvin"}; var service = new Mock<ICommentService>(); service.Setup(s => s.Get(123)).Returns(feedback); service.Setup(s => s.Destroy(123)); var controller = new CommentController(service.Object); // act var result = controller.Destroy(123) as JsonResult; // assert service.Verify(c => c.Destroy(123)); var data = new RouteValueDictionary(result.Data); Assert.AreEqual("Comment by Calvin", data["subject"]); Assert.AreEqual("was destroyed (there is no undo)", data["predicate"]); }
public void ConvertToAkismetItem_WithFeedback_SetsProperties() { // arrange var feedback = new FeedbackItem(FeedbackType.ContactPage) { SourceUrl = new Uri("http://example.com/author-source") }; var urlHelper = new Mock<BlogUrlHelper>(); urlHelper.Setup(helper => helper.FeedbackUrl(It.IsAny<FeedbackItem>())).Returns("/foo"); urlHelper.Setup(helper => helper.BlogUrl()).Returns("/"); var service = new AkismetSpamService("abracadabra", new Blog { Host = "localhost" }, null, urlHelper.Object); // act var comment = service.ConvertToAkismetItem(feedback); // assert Assert.AreEqual("http://example.com/author-source", comment.AuthorUrl.ToString()); Assert.AreEqual("http://localhost/foo", comment.Permalink.ToString()); }
public int Create(FeedbackItem comment, bool runFilters) { Entry entry = Cacher.GetEntry(comment.EntryId, SubtextContext); if (entry != null && entry.CommentingClosed) { return NullValue.NullInt32; } ISubtextContext context = SubtextContext; HttpContextBase httpContext = context.HttpContext; if (httpContext != null && httpContext.Request != null) { comment.UserAgent = httpContext.Request.UserAgent; comment.IpAddress = HttpHelper.GetUserIpAddress(httpContext); } if (runFilters) { comment.FlaggedAsSpam = true; //We're going to start with this assumption. } comment.Author = HtmlHelper.SafeFormat(comment.Author, context.HttpContext.Server); comment.Body = HtmlHelper.ConvertUrlsToHyperLinks(HtmlHelper.ConvertToAllowedHtml(comment.Body)); comment.Title = HtmlHelper.SafeFormat(comment.Title, context.HttpContext.Server); comment.Entry = entry; comment.DateCreatedUtc = comment.DateCreatedUtc.IsNull() ? DateTime.UtcNow : comment.DateCreatedUtc; comment.DateModifiedUtc = comment.DateModifiedUtc.IsNull() ? DateTime.UtcNow : comment.DateModifiedUtc; if (runFilters) { OnBeforeCreate(comment); } comment.Id = Repository.Create(comment); if (runFilters) { OnAfterCreate(comment); } return comment.Id; }
public void Create(int id, [ModelBinder(typeof(XmlModelBinder))] XmlDocument xml) { if (xml == null) { throw new ArgumentNullException("xml"); } var comment = new FeedbackItem(FeedbackType.Comment) { CreatedViaCommentApi = true }; string name = (xml.SelectSingleNode("//item/author") ?? Empty).InnerText; if (name.IndexOf("<") != -1) { name = name.Substring(0, name.IndexOf("<")); } comment.Author = name.Trim(); comment.Body = (xml.SelectSingleNode("//item/description") ?? Empty).InnerText; comment.Title = (xml.SelectSingleNode("//item/title") ?? Empty).InnerText; comment.SourceUrl = HtmlHelper.EnsureUrl((xml.SelectSingleNode("//item/link") ?? Empty).InnerText); comment.EntryId = id; CommentService.Create(comment, true/*runFilters*/); }
public void CannotCreateMoreThanOneCommentWithinDelay() { Assert.IsTrue(Config.CreateBlog("", "username", "password", _hostName, string.Empty)); BlogInfo blog = Config.CurrentBlog; blog.CommentDelayInMinutes = 1; FeedbackItem trackback = new FeedbackItem(FeedbackType.PingTrack); trackback.DateCreated = DateTime.Now; trackback.SourceUrl = new Uri("http://localhost/ThisUrl/"); trackback.Title = "Some Title"; trackback.Body = "Some Body Some Body"; FeedbackItem.Create(trackback, new CommentFilter(HttpContext.Current.Cache)); Thread.Sleep(100); FeedbackItem comment = new FeedbackItem(FeedbackType.Comment); comment.DateCreated = DateTime.Now; comment.SourceUrl = new Uri("http://localhost/ThisUrl/"); comment.Title = "Some Title"; comment.Body = "Some Body Else"; FeedbackItem.Create(comment, new CommentFilter(HttpContext.Current.Cache)); }
public void FilterAfterPersistWithCommentModerationDisabledCausesNewCommentsToBeActive() { //arrange var subtextContext = new Mock<ISubtextContext>(); var cache = new TestCache(); subtextContext.Setup(c => c.Cache).Returns(cache); subtextContext.Setup(c => c.User.IsInRole("Admins")).Returns(false); subtextContext.Setup(c => c.Blog).Returns(new Blog { ModerationEnabled = false }); FeedbackItem savedFeedback = null; subtextContext.Setup(c => c.Repository.UpdateInternal(It.IsAny<FeedbackItem>())).Callback<FeedbackItem>( f => savedFeedback = f); var commentSpamFilter = new Mock<ICommentSpamService>(); var commentFilter = new CommentFilter(subtextContext.Object, commentSpamFilter.Object); var feedback = new FeedbackItem(FeedbackType.Comment) { }; Assert.IsFalse(feedback.Approved); //act commentFilter.FilterAfterPersist(feedback); //assert Assert.IsTrue(savedFeedback.Approved); }
public Comment ConvertToAkismetItem(FeedbackItem feedback) { var comment = new Comment(feedback.IpAddress, feedback.UserAgent) { Author = feedback.Author ?? string.Empty, AuthorEmail = feedback.Email }; if (feedback.SourceUrl != null) { comment.AuthorUrl = feedback.SourceUrl; } comment.Content = feedback.Body; comment.Referrer = feedback.Referrer; var feedbackUrl = _urlHelper.FeedbackUrl(feedback); if (feedbackUrl != null) { Uri permalink = feedbackUrl.ToFullyQualifiedUrl(_blog); if (permalink != null) { comment.Permalink = permalink; } } comment.CommentType = feedback.FeedbackType.ToString().ToLower(CultureInfo.InvariantCulture); return comment; }
// Returns true if the source of the entry is not // posting too many. bool SourceFrequencyIsValid(FeedbackItem feedbackItem) { if (Blog.CommentDelayInMinutes <= 0) { return true; } object lastComment = Cache[FilterCacheKey + feedbackItem.IpAddress]; if (lastComment != null) { //Comment was made too frequently. return false; } //Add to cache. Cache.Insert(FilterCacheKey + feedbackItem.IpAddress, string.Empty, null, DateTime.UtcNow.AddMinutes(Blog.CommentDelayInMinutes), TimeSpan.Zero); return true; }
// Returns true if this entry is a duplicate. bool IsDuplicateComment(FeedbackItem feedbackItem) { const int recentEntryCapacity = 10; if (Cache == null) { return false; } // Check the cache for the last 10 comments // Chances are, if a spam attack is occurring, then // this entry will be a duplicate of a recent entry. // This checks in memory before going to the database (or other persistent store). var recentCommentChecksums = Cache[FilterCacheKey + ".RECENT_COMMENTS"] as Queue<string>; if (recentCommentChecksums != null) { if (recentCommentChecksums.Contains(feedbackItem.ChecksumHash)) { return true; } } else { recentCommentChecksums = new Queue<string>(recentEntryCapacity); Cache[FilterCacheKey + ".RECENT_COMMENTS"] = recentCommentChecksums; } // Check the database FeedbackItem duplicate = SubtextContext.Repository.GetFeedbackByChecksumHash(feedbackItem.ChecksumHash); if (duplicate != null) { return true; } //Ok, this is not a duplicate... Update recent comments. if (recentCommentChecksums.Count == recentEntryCapacity) { recentCommentChecksums.Dequeue(); } recentCommentChecksums.Enqueue(feedbackItem.ChecksumHash); return false; }
private void FlagAsSpam(FeedbackItem feedbackItem) { feedbackItem.FlaggedAsSpam = true; feedbackItem.Approved = false; SubtextContext.Repository.Update(feedbackItem); }
/// <summary> /// Validates the feedback before it has been persisted. /// </summary> /// <param name="feedback"></param> /// <exception type="CommentFrequencyException">Thrown if too many comments are received from the same source in a short period.</exception> /// <exception type="CommentDuplicateException">Thrown if the blog does not allow duplicate comments and too many are received in a short period of time.</exception> public void FilterBeforePersist(FeedbackItem feedback) { if (!SubtextContext.User.IsAdministrator()) { if (!SourceFrequencyIsValid(feedback)) { throw new CommentFrequencyException(Blog.CommentDelayInMinutes); } if (!Blog.DuplicateCommentsEnabled && IsDuplicateComment(feedback)) { throw new CommentDuplicateException(); } } }