Well, that didn't take long...

by Kai 21. September 2008 00:42

I've been using this Post Security Extension that allows you to set privacy settings for posts.  In a nutshell it works by comparing categories assigned to a post to extension settings that map those categories to user roles.  It works pretty well, but I did want to make a few modifications, including

  1. Authors can always see their own posts
  2. Members of role "Administrators" can always see all posts
  3. Comments are now also screened for permissions at Serve time (it was either that or not allow posting comments for posts in restricted categories, which would have had other problems as well).
  4. A user can view the post/comment if they are in ANY of the roles instead of ALL of them.  Originally, the extension only let you see the post if you belonged to ALL the restricted categories.  For example, if I have a post tagged with restricted categories "Friends" and "Family", I intend for the post to be visible by either Friends, or Family.
  5. If you set up a restricted category and don't mention an associated role, it affects NO post, instead of ALL posts. 

The code for the updated PostSecurity extension is at the end of this post.  Even though it's more or less a complete re-write of the original, I didn't change the name of it because it shouldn't be used at the same time as the original extension.

You don't need to do the next part if you're okay with the post/comment references showing up in some places.  In other words, the changes made to the extension do not require the following core code changes.

This extension relies on the BlogEngine.Net event Post.Serving. Unfortunately, BlogEngine.Net doesn't fire that event in every case that post/comment info is displayed to potential readers.  I found that the post is still referenced under the following conditions:

  1. Recent Posts Widget
  2. Recent Comments Widget
  3. Various searches including related posts and standard search

That doesn't really work for me, so even though I didn't really want to do this, I modified the source of BlogEngine.Net to fire the Serving event under those circumstances.  Hopefully I caught them all.

Here are the edits:

BlogEngine.Web\widgets\RecentComments\widget.ascx.cs

   1: private string RenderComments(List<Comment> comments, StringDictionary settings)
   2:     {
   3:         if (comments.Count == 0)
   4:         {
   5:             //HttpRuntime.Cache.Insert("widget_recentcomments", "<p>" + Resources.labels.none + "</p>");
   6:             return "<p>" + Resources.labels.none + "</p>";
   7:         }
   8:  
   9:         HtmlGenericControl ul = new HtmlGenericControl("ul");
  10:         ul.Attributes.Add("class", "recentComments");
  11:         ul.ID = "recentComments";
  12:  
  13:         foreach (Comment comment in comments)
  14:         {
  15:             /* CUSTOM CODE */
  16:             ServingEventArgs arg = new ServingEventArgs(comment.Content, ServingLocation.Other);
  17:             comment.OnServing(arg);
  18:             if (arg.Cancel)
  19:             {
  20:                 continue;
  21:             }
  22:             /* END CUSTOM CODE */
  23:  
  24:             if (comment.IsApproved)
  25:             {
  26:                 HtmlGenericControl li = new HtmlGenericControl("li");
  27:  
  28:                 // The post title
  29:                 HtmlAnchor title = new HtmlAnchor();
  30:                 title.HRef = comment.Parent.RelativeLink.ToString();
  31:                 title.InnerText = comment.Parent.Title;
  32:                 title.Attributes.Add("class", "postTitle");
  33:                 li.Controls.Add(title);
  34:  
  35:                 // The comment count on the post
  36:                 LiteralControl count = new LiteralControl(" (" + ((Post)comment.Parent).ApprovedComments.Count + ")<br />");
  37:                 li.Controls.Add(count);
  38:  
  39:                 // The author
  40:                 if (comment.Website != null)
  41:                 {
  42:                     HtmlAnchor author = new HtmlAnchor();
  43:                     author.Attributes.Add("rel", "nofollow");
  44:                     author.HRef = comment.Website.ToString();
  45:                     author.InnerHtml = comment.Author;
  46:                     li.Controls.Add(author);
  47:  
  48:                     LiteralControl wrote = new LiteralControl(" " + Resources.labels.wrote + ": ");
  49:                     li.Controls.Add(wrote);
  50:                 }
  51:                 else
  52:                 {
  53:                     LiteralControl author = new LiteralControl(comment.Author + " " + Resources.labels.wrote + ": ");
  54:                     li.Controls.Add(author);
  55:                 }
  56:  
  57:                 // The comment body
  58:                 string commentBody = Regex.Replace(comment.Content, @"\[(.*?)\]", "");
  59:                 int bodyLength = Math.Min(commentBody.Length, 50);
  60:  
  61:                 commentBody = commentBody.Substring(0, bodyLength);
  62:                 if (commentBody.Length > 0)
  63:                 {
  64:                     if (commentBody[commentBody.Length - 1] == '&')
  65:                     {
  66:                         commentBody = commentBody.Substring(0, commentBody.Length - 1);
  67:                     }
  68:                 }
  69:                 commentBody += comment.Content.Length <= 50 ? " " : "… ";
  70:                 LiteralControl body = new LiteralControl(commentBody);
  71:                 li.Controls.Add(body);
  72:  
  73:                 // The comment link
  74:                 HtmlAnchor link = new HtmlAnchor();
  75:                 link.HRef = comment.Parent.RelativeLink + "#id_" + comment.Id;
  76:                 link.InnerHtml = "[" + Resources.labels.more + "]";
  77:                 link.Attributes.Add("class", "moreLink");
  78:                 li.Controls.Add(link);
  79:  
  80:                 ul.Controls.Add(li);
  81:             }
  82:         }
  83:  
  84:         StringWriter sw = new StringWriter();
  85:         ul.RenderControl(new HtmlTextWriter(sw));
  86:  
  87:         string ahref = "<a href=\"{0}syndication.axd?comments=true\">Comment RSS <img src=\"{0}pics/rssButton.gif\" alt=\"\" /></a>";
  88:         string rss = string.Format(ahref, Utils.RelativeWebRoot);
  89:         sw.Write(rss);
  90:         return sw.ToString();
  91:         //HttpRuntime.Cache.Insert("widget_recentcomments", sw.ToString());
  92:     }

BlogEngine.Web\widgets\RecentPosts\widget.ascx.cs

   1: private string RenderPosts(List<Post> posts, StringDictionary settings)
   2:     {
   3:         if (posts.Count == 0)
   4:         {
   5:             //HttpRuntime.Cache.Insert("widget_recentposts", "<p>" + Resources.labels.none + "</p>");
   6:             return "<p>" + Resources.labels.none + "</p>";
   7:         }
   8:  
   9:         StringBuilder sb = new StringBuilder();
  10:         sb.Append("<ul class=\"recentPosts\" id=\"recentPosts\">");
  11:  
  12:         foreach (Post post in posts)
  13:         {
  14:             if (!post.IsVisible)
  15:                 continue;
  16:  
  17:             /* CUSTOM CODE */
  18:             ServingEventArgs arg = new ServingEventArgs(post.Content, ServingLocation.Other);
  19:             post.OnServing(arg);
  20:             if (arg.Cancel)
  21:             {
  22:                 continue;
  23:             }
  24:             /* END CUSTOM CODE */
  25:  
  26:             string rating = Math.Round(post.Rating, 1).ToString(System.Globalization.CultureInfo.InvariantCulture);
  27:  
  28:             string link = "<li><a href=\"{0}\">{1}</a>{2}{3}</li>";
  29:             string comments = string.Format("<span>{0}: {1}</span>", Resources.labels.comments, post.ApprovedComments.Count);
  30:             string rate = string.Format("<span>{0}: {1} / {2}</span>", Resources.labels.rating, rating, post.Raters);
  31:  
  32:             bool showComments = DEFAULT_SHOW_COMMENTS;
  33:             bool showRating = DEFAULT_SHOW_RATING;
  34:             if (settings.ContainsKey("showcomments") && settings["showcomments"].Equals("false", StringComparison.OrdinalIgnoreCase))
  35:                 showComments = false;
  36:  
  37:             if (settings.ContainsKey("showrating") && settings["showrating"].Equals("false", StringComparison.OrdinalIgnoreCase))
  38:                 showRating = false;
  39:  
  40:             if (!showComments || !BlogSettings.Instance.IsCommentsEnabled)
  41:                 comments = null;
  42:  
  43:             if (!showRating || !BlogSettings.Instance.EnableRating)
  44:                 rate = null;
  45:  
  46:             if (post.Raters == 0)
  47:                 rating = Resources.labels.notRatedYet;
  48:  
  49:             sb.AppendFormat(link, post.RelativeLink, HttpUtility.HtmlEncode(post.Title), comments, rate);
  50:         }
  51:  
  52:         sb.Append("</ul>");
  53:         //HttpRuntime.Cache.Insert("widget_recentposts", sb.ToString());
  54:         return sb.ToString();
  55:     }

BlogEngine.Core\Search.cs

   1: public static List<IPublishable> Hits(string searchTerm, bool includeComments)
   2:         {
   3:             lock (_SyncRoot)
   4:             {
   5:                 List<Result> results = BuildResultSet(searchTerm, includeComments);
   6:                 List<IPublishable> items = results.ConvertAll(new Converter<Result, IPublishable>(ResultToPost));
   7:                 results.Clear();
   8:                 OnSearcing(searchTerm);
   9:  
  10:                 /* CUSTOM CODE */
  11:                 int i = 0;
  12:                 while(i < items.Count)
  13:                 {
  14:                     IPublishable p = items[i];
  15:                     ServingEventArgs arg = new ServingEventArgs(p.Content, ServingLocation.Other);
  16:                     p.OnServing(arg);
  17:                     if (arg.Cancel)
  18:                     {
  19:                         items.RemoveAt(i);
  20:                     }
  21:                     else
  22:                     {
  23:                         i++;
  24:                     }
  25:                 }
  26:                 /* END CUSTOM CODE */
  27:  
  28:                 return items;
  29:             }
  30:         }

BlogEngine.Core\Search.cs

   1: public static List<IPublishable> ApmlMatches(XmlDocument apmlFile, int maxInterests)    2: {
   3:     Dictionary<string, float> concepts = new Dictionary<string, float>();
   4:     XmlNodeList nodes = apmlFile.SelectNodes("//Concept");
   5:     foreach (XmlNode node in nodes)
   6:     {
   7:         string key = node.Attributes["key"].InnerText.ToLowerInvariant().Trim();
   8:         float value = float.Parse(node.Attributes["value"].InnerText, System.Globalization.CultureInfo.InvariantCulture);
   9:         if (!concepts.ContainsKey(key))
  10:         {
  11:             concepts.Add(key, value);
  12:         }
  13:         else if (concepts[key] < value)
  14:         {
  15:             concepts[key] = value;
  16:         }
  17:     }
  18:  
  19:     concepts = SortDictionary(concepts);
  20:     int max = Math.Min(concepts.Count, maxInterests);
  21:     int counter = 0;
  22:     List<Result> resultSet = new List<Result>();
  23:     foreach (string key in concepts.Keys)
  24:     {
  25:         counter++;
  26:         List<Result> results = BuildResultSet(key, false);
  27:         //results = results.FindAll(delegate(Result r) { return r.Rank > 1; });
  28:         resultSet.AddRange(results);
  29:         if (counter == max)
  30:             break;
  31:     }
  32:  
  33:     resultSet.Sort();
  34:     List<Result> aggregatedResults = new List<Result>();
  35:     foreach (Result r in resultSet)
  36:     {
  37:         if (!aggregatedResults.Contains(r))
  38:         {
  39:             aggregatedResults.Add(r);
  40:         }
  41:         else
  42:         {
  43:             Result existingResult = aggregatedResults.Find(delegate(Result res) { return res.GetHashCode() == r.GetHashCode(); });
  44:             existingResult.Rank += r.Rank;
  45:         }
  46:     }
  47:  
  48:     aggregatedResults = aggregatedResults.FindAll(delegate(Result r) { return r.Rank > 1; });
  49:     List<IPublishable> items = aggregatedResults.ConvertAll(new Converter<Result, IPublishable>(ResultToPost));
  50:     List<IPublishable> uniqueItems = new List<IPublishable>();
  51:  
  52:     
  53:     foreach (IPublishable item in items)
  54:     {
  55:         /* CUSTOM CODE */
  56:         ServingEventArgs arg = new ServingEventArgs(item.Content, ServingLocation.Other);
  57:         item.OnServing(arg);
  58:         /* END CUSCOM CODE */
  59:  
  60:         if (!uniqueItems.Contains(item) && !arg.Cancel)
  61:             uniqueItems.Add(item);
  62:     }
  63:  
  64:     return uniqueItems;
  65: }

PostSecurity.CS updates:  PostSecurity.cs (4.04 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

BlogEngine.Net

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About Me

My name is Kai Steinmann. This is my blog. :)

I'm a video Game Developer by trade.  On my blog you'll find various wanderings about Game Development, Games in general, C# and .NET programming as well as other random stuff that interests me that day. 

Thanks for stopping by.