A reader (or two or three etc?) of my blog here makes the occasional one-star rating without sharing a comment. Sometimes this is fair and deserved.
Sometimes, however, I don't care what the heck you guys think of a few of my posts, because these occasional posts might be very personal, UNLESS you share your thoughts in comments. Thumbs-down is generally rude unless you post a comment with constructive criticism. I can take constructive criticism far better than I can take "this post sucks".
So I decided I wanted to be able to both ban visitors by IP address and disable ratings per post. The ban list can be maintained in SQL, and by the way the solution here is usable anywhere, not just BlogEngine.net (although it has no effect for FeedBurner RSS/Atom subscribers), but the other feature of per-post ratings disablement I felt should complement the "Enable Comments" feature in the post editor. These were two easy changes, so I'll make this quick.
Banning Users (Usable On Any ASP.NET Web Site)
Add a SQL table (IPAddress column is nullable so that other types of bans can be added later):
/****** Object: Table [dbo].[Bans] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Bans](
[id] [int] IDENTITY(1,1) NOT NULL,
[IPAddress] [varchar](15) NULL,
CONSTRAINT [PK_Bans] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
Add a new class file in the App_Code directory:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Data.SqlClient;
using System.Configuration;
public class SiteUtil
{
public static bool IPIsBanned
{
get
{
try {
IPAddress remoteIP = IPAddress.Parse(HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]);
return BannedIPs.Find(addr => addr.ToString() == remoteIP.ToString()) != null;
} catch {
return false;
}
}
}
private static List<IPAddress> _BannedIPs = null;
private static DateTime? _BannedIPs_TimeStamp = null;
public static List<IPAddress> BannedIPs
{
get
{
if (_BannedIPs == null || (_BannedIPs_TimeStamp != null &&
((TimeSpan)(DateTime.Now - _BannedIPs_TimeStamp.Value)).Ticks > TimeSpan.TicksPerHour))
{
_BannedIPs = new List<IPAddress>();
using (SqlConnection conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString))
{
conn.Open();
string ssql = "SELECT IPAddress FROM Bans WHERE IPAddress IS NOT NULL";
using (SqlCommand cmd = new SqlCommand(ssql, conn))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
_BannedIPs.Add(IPAddress.Parse((string)dr["IPAddress"]));
}
_BannedIPs_TimeStamp = DateTime.Now;
}
}
}
}
return _BannedIPs;
}
}
}
Add to global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (SiteUtil.IPIsBanned) Response.Redirect("http://www.albinoblacksheep.com/flash/youare");
}
Per-Article Ratings
Add SQL column:
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.be_Posts ADD
IsRatingEnabled bit NOT NULL CONSTRAINT DF_be_Posts_IsRatingEnabled DEFAULT 1
GO
COMMIT
Create ~/themes/{theme}/MyPostView.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using System.Configuration;
public partial class MyPostView : BlogEngine.Core.Web.Controls.PostViewBase
{
protected override string Rating
{
get
{
return this.IsRatable ? base.Rating : "";
}
}
protected bool IsRatable
{
get
{
return BlogEngine.Core.BlogSettings.Instance.EnableRating
&& !RatingDisabled(this.Post.Id);
}
}
protected List<Guid> _RatingDisabledPosts = null;
protected DateTime? _RatingDisabledPosts_TimeStamp = null;
protected bool RatingDisabled(Guid postId)
{
if (_RatingDisabledPosts == null || (_RatingDisabledPosts_TimeStamp.HasValue &&
(DateTime.Now - _RatingDisabledPosts_TimeStamp.Value).Ticks > TimeSpan.TicksPerHour))
{
using (SqlConnection conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString))
{
conn.Open();
string ssql = "SELECT PostID FROM be_Posts WHERE IsRatingEnabled = 0";
using (SqlCommand cmd = new SqlCommand(ssql, conn))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
_RatingDisabledPosts = new List<Guid>();
while (dr.Read())
{
_RatingDisabledPosts.Add((Guid)dr["PostID"]);
}
_RatingDisabledPosts_TimeStamp = DateTime.Now;
}
}
}
}
return _RatingDisabledPosts.Contains(postId);
}
}
Modify header line of ~/themes/{theme}/PostView.ascx:
<%@ Control Language="C#" AutoEventWireup="true" EnableViewState="false" Inherits="MyPostView"
CodeFile="~/themes/Standard/MyPostView.aspx.cs" %>
Modify ~/admin/Pages/Add_entry.aspx (add cbEnableRating between the two other checkboxes):
<asp:CheckBox runat="server" ID="cbEnableComments" Text="<%$ Resources:labels, enableComments %>" Checked="true" TabIndex="14" />
<asp:CheckBox runat="server" ID="cbEnableRating" Text="<%$ Resources:labels, enableRating %>" Checked="true" TabIndex="15" />
<asp:CheckBox runat="server" ID="cbPublish" Text="<%$ Resources:labels, publish %>" Checked="true" TabIndex="16" />
Modify ~/admin/Pages/Add_entry.aspx.cs:
// cbEnableRating: generally follow cbEnableComments
protected void Page_Load(object sender, EventArgs e)
{
...
if (!String.IsNullOrEmpty(Request.QueryString["id"]) && Request.QueryString["id"].Length == 36)
{
...
}
else
{
...
cbEnableRating.Checked = BlogSettings.Instance.EnableRating;
...
}
...
cbEnableRating.Enabled = BlogSettings.Instance.EnableRating;
}
private void btnSave_Click(object sender, EventArgs e)
{
...
post.Save();
using (SqlConnection conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString))
{
conn.Open();
string ssql = "UPDATE be_Posts SET IsRatingEnabled = @enabled WHERE PostID = @PostID";
using (SqlCommand cmd = new SqlCommand(ssql, conn))
{
cmd.Parameters.Add("@enabled", System.Data.SqlDbType.Bit).Value
= cbEnableRating.Checked;
cmd.Parameters.Add("@PostID", System.Data.SqlDbType.UniqueIdentifier).Value
= post.Id;
cmd.ExecuteNonQuery();
}
}
...
}
private void BindPost(Guid postId)
{
...
using (SqlConnection conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["BlogEngine"].ConnectionString))
{
conn.Open();
string ssql = "SELECT IsRatingEnabled FROM be_Posts WHERE PostID = @PostID";
using (SqlCommand cmd = new SqlCommand(ssql, conn))
{
cmd.Parameters.Add("@PostID", System.Data.SqlDbType.UniqueIdentifier).Value =
post.Id;
using (SqlDataReader dr = cmd.ExecuteReader())
{
dr.Read();
cbEnableRating.Checked = (bool)dr["IsRatingEnabled"];
}
}
}
}