CS Nuggets

This blog is for addons, bugs, fixes, and issues pertaining to Community Server.

April 2007 - Posts

CS2007: BUG & FIX: BBCodes and Emoticons

This bug is a carry over from CS 2.x which improperly handles BBCodes and Emoticons.  You can see this on the communityserver.org site.  Every so often you will see a post with smilies that seem out of place, or you may be trying to use BBCodes and they don't quite work properly.  This is mostly due to the order in which things are being processed.

This fix requires making changes to the SDK, will correct these issues, and add 3 new BBCodes (

, [notes], and [ which is a BBCode escape for code lists).  The [code] BBCode is a standard code, but it was left out of the CS library.  To make these changes, do the following:

File: CommunityServerComponents20/Components/Transforms.cs:

Around line 53:

Move the following lines:

if (allowCustomTransforms ) {
    // must do emoteicons first because they are restricted from finding any inside [code]
blocks. We have to do
    // this before the later steps remove the
blocks.
    if( CSContext.Current.SiteSettings.EnableEmoticons ) {
        formattedPost = EmoticonTransforms(formattedPost);
    }
}

to line 76, after the following lines:

// Do BBCode transform, if any
//
formattedPost = BBcodeToHtml(formattedPost);

Around Line 240: 

After the following lines:

// Left, Right, Center
encodedString = Regex.Replace(encodedString, @"\[left(?:\s*)\]((.|\n)*?)\[/left(?:\s*)]", "<div style=\"text-align:left\">$1</div>", options);
encodedString = Regex.Replace(encodedString, @"\[center(?:\s*)\]((.|\n)*?)\[/center(?:\s*)]", "<div style=\"text-align:center\">$1</div>", options);
encodedString = Regex.Replace(encodedString, @"\[right(?:\s*)\]((.|\n)*?)\[/right(?:\s*)]", "<div style=\"text-align:right\">$1</div>", options);

insert:

// Note
//
encodedString = Regex.Replace(encodedString, @"\[note(?:\s*)header=(?:""|&quot;|&#34;)(.*?)(?:""|&quot;|&#34;)\]", "<blockquote><div><strong>$1:</strong></div><br /><div>", options);
encodedString = Regex.Replace(encodedString, @"\[note(\s*)\]", "<blockquote><div>", options);
encodedString = Regex.Replace(encodedString, @"\[/note(\s*)\]", "</div></blockquote>", options);

// Code
//
encodedString = Regex.Replace(encodedString, @"\[code(?:\s*)file=(?:""|&quot;|&#34;)(.*?)(?:""|&quot;|&#34;)\]", "<blockquote style=\"overflow-x: scroll;\"><div><strong>$1:</strong></div><br /><pre style=\"margin: 0px;\">", options);
encodedString = Regex.Replace(encodedString, @"\[code(?:\s*)\]", "<blockquote style=\"overflow-x: scroll;\"><pre style=\"margin: 0px;\">", options);
encodedString = Regex.Replace(encodedString, @"\[/code(?:\s*)\]", "</pre></blockquote>", options);

Around line 295:

Before the following line:

return encodedString;

insert:

// New code for developers
encodedString = Regex.Replace(encodedString, @"\[\]", "[", options);

File: communityserver.config:

In the <CSModules> section around line 1020:

Find the following section:

<add name = "AutoApproveForumModule" type="CommunityServer.Discussions.Components.AutoApproveForumModule, CommunityServer.Discussions" />
<add name = "BBcodeToHtml" type = "CommunityServer.Discussions.Components.BBcodeToHtmlModule, CommunityServer.Discussions" />
<add name = "IrcCommands" type = "CommunityServer.Discussions.Components.IrcCommandsModule, CommunityServer.Discussions" />
<add name = "ForumCensorship" type = "CommunityServer.Discussions.Components.CensorshipModule, CommunityServer.Discussions" />
<add name = "ForumEmoticon" type = "CommunityServer.Discussions.Components.EmoticonModule, CommunityServer.Discussions" />
<add name = "ForumSourceCode" type = "CommunityServer.Discussions.Components.SourceCodeModule, CommunityServer.Discussions" />
<add name = "ForumPlainText" type = "CommunityServer.Discussions.Components.PlainTextModule, CommunityServer.Discussions" />
<add name = "ForumHtmlScrubbing" type = "CommunityServer.Discussions.Components.HtmlScrubbingModule, CommunityServer.Discussions" />
<add name = "ForumCollapse" type = "CommunityServer.Discussions.Components.CollapseModule, CommunityServer.Discussions" />
<add name="ForumQuoteModule" type="CommunityServer.Discussions.Components.QuoteModule, CommunityServer.Discussions" />

and change the order of the lines to:

<add name = "AutoApproveForumModule" type="CommunityServer.Discussions.Components.AutoApproveForumModule, CommunityServer.Discussions" />
<add name = "IrcCommands" type = "CommunityServer.Discussions.Components.IrcCommandsModule, CommunityServer.Discussions" />
<add name = "ForumCensorship" type = "CommunityServer.Discussions.Components.CensorshipModule, CommunityServer.Discussions" />
<add name = "ForumSourceCode" type = "CommunityServer.Discussions.Components.SourceCodeModule, CommunityServer.Discussions" />
<add name = "ForumPlainText" type = "CommunityServer.Discussions.Components.PlainTextModule, CommunityServer.Discussions" />
<add name = "ForumHtmlScrubbing" type = "CommunityServer.Discussions.Components.HtmlScrubbingModule, CommunityServer.Discussions" />
<add name = "BBcodeToHtml" type = "CommunityServer.Discussions.Components.BBcodeToHtmlModule, CommunityServer.Discussions" />
<add name = "ForumEmoticon" type = "CommunityServer.Discussions.Components.EmoticonModule, CommunityServer.Discussions" />

<add name = "ForumCollapse" type = "CommunityServer.Discussions.Components.CollapseModule, CommunityServer.Discussions" />
<add name="ForumQuoteModule" type="CommunityServer.Discussions.Components.QuoteModule, CommunityServer.Discussions" />

The new [code] BBCode has an optional file="<text>" attribute that you can use for filenames or whatever else you would like.  The new [note] BBCode has an optional header="<text>" attribute that works in the same way as the file attribute of [code].  To use the new code for developers, you just type a ] (right bracket) immediately after an [ (left bracket).  For example, entering:

[b]This is how you bold text[/b]

in your post, will display:

This is how you bold text

And if you entered the above line directly into a post it would display as:

This is how you bold text

If you have any questions or comments, please post them here.  Also, if you haven't already read my post CS2007: Add BBCode support to Blogs, you may to read it as well.

Posted: Sun, Apr 29 2007 11:43 PM by Bill Bosacker | with no comments
Filed under: ,
CS2007: BUG & FIX: Aggregate Post Excerpt Size

There appears to be a bug with Control Panel / Administration / Blogs / Default Presentation / Aggregate Post Excerpt Size.  While you can set this value, it does not appear that it is actually being used.  It should limit the size of excerpts in aggregate lists, but it isn't.  The following one line change requires access to the SDK:

File: CommunityServerBogs20/Components/WeblogPost.cs:

At or around line 267, change the following line:

get{return GetInt("ExcerptSize",250);}

to

get{return GetInt("ExcerptSize",WeblogConfiguration.Instance().AggregatePostSize);}

Posted: Sun, Apr 29 2007 07:26 PM by Bill Bosacker | with no comments
Filed under: ,
CS2007: My Blogs

People who know a lot about Community Server, know that if you want to navigate to your blog you need to go to Blogs / Blogs on this Site / <your blog>.  The problem is that most people either don't see or don't think about using the Blogs on the Site link.  It is also quite a few things to click on.  In the post "Control Panel" button not showing up for logged in users, people have made the Control Panel available to everyone who is logged in, which really isn't a very good idea.

For CS 2.1, I wrote CS: How to add "My Blogs" to the menu tabs which adds a new tab to the menu bar, but it too can be a little confusing and clutters the menu bar if you have a lot of buttons.  So, for Community Server 2007 I took my modification from CS 2.1 and added a My Blogs link to the Blogs page.  Here is the changes:

Create 'Blog Owners' role:

  1. Navigate your way to Control Panel / Administration / Membership / Manage All Roles and click on Add New Role.
  2. Enter Blog Owners as the name and click Save.
  3. Add the Blog Owners role to each member that is allowed to post to any blog.

If you do not wish to create and/or manage this role, then change all references to Blog Owners in the following code to Registered Users (note the space), and this link will be visible to all registered users, but will only be useful to those who can post to a blog.

File: CommunityServerWeb20 (Internal)/Themes/<theme name>/Blogs/blogs.Master:

In each site theme, inside of the DIV tags that use the CommonSidebarContent class, insert the following lines after both of the <ContentTemplate> open elements:

<CSControl:SiteUrl ResourceName="MyWeblogs" UrlName="blog_ControlPanel_Switch" Tag="Li" runat="server">
    <DisplayConditions><CSControl:UserInRoleCondition UseAccessingUser="true" Role="Blog Owners" runat="server" /></DisplayConditions>
</CSControl:SiteUrl>

This will add the My Blogs link to the sidebar just above the RSS feed link, if the user is a member of the Blog Owners group.

CS2007: Add BBCode support to Blogs

Back in 2006 I noticed that BBCodes weren't supported in blogs, so I created the post New Functionality: BBCodes in Blogs to correct this very serious oversight.  The same issue exists in CS 2007, so its time to rectify this egregious shortcoming.  To do this you can either install Community Server Addons v1.1 for .NET 2.0 or make the following changes to the SDK:

Create a new class CommunityServerBlogs20/Components/Modules/WeblogBBCodeModule.cs and replace the contents of the newly created class file with:

using System;
using System.Xml;
using CommunityServer.Components;

namespace CommunityServer.Blogs.Components
{
    /// <summary>
    ///     Summary description for WeblogBBCodeModule.
    /// </summary>
    public class WeblogBBCodeModule : ICSModule
    {
        public WeblogBBCodeModule() { }

        public void Init(CSApplication csa, XmlNode node)
        {
            csa.PrePostUpdate += new CSPostEventHandler(csa_PrePostUpdate);
        }

        private void csa_PrePostUpdate(IContent content, CSPostEventArgs e)
        {
            if (e.ApplicationType == ApplicationType.Weblog)
            {
                WeblogPost wp = content as WeblogPost;
                if (wp != null && e.State != ObjectState.Delete)
                {
                    wp.FormattedBody = Transforms.BBcodeToHtml(wp.FormattedBody);
                }
            }
        }
    }
}

Then within the CommunityServer/CSModules element of the communityserver.config file, find the following block and insert the bolded line:

<add name = "MetaBlogExtender" type = "CommunityServer.Blogs.Components.MetaBlogExtender, CommunityServer.Blogs" />
<add name = "PostandArticleTokens" type = "CommunityServer.Blogs.Components.PostandArticleTokens, CommunityServer.Blogs" />
<add name = "WeblogCensorModule" type = "CommunityServer.Blogs.Components.CensorModule, CommunityServer.Blogs" />
<add name = "WeblogPostandArticleHtmlScrubbing" type = "CommunityServer.Blogs.Components.PostandArticleHtmlScrubbing, CommunityServer.Blogs" />
<add name = "WeblogFeedbackHtmlFormatting" type = "CommunityServer.Blogs.Components.FeedbackHtmlFormatting, CommunityServer.Blogs" />
<add name = "WeblogFormattingModule" type = "CommunityServer.Blogs.Components.WeblogFormattingModule, CommunityServer.Blogs" />
<add name = "WeblogBBCodeModule" type = "CommunityServer.Blogs.Components.WeblogBBCodeModule, CommunityServer.Blogs" />
<add name = "WeblogEmoticonsModule" type = "CommunityServer.Blogs.Components.WeblogEmoticonsModule, CommunityServer.Blogs" />
<add name = "TrackbackModule" type = "CommunityServer.Blogs.Components.TrackbackModule, CommunityServer.Blogs" />
<add name = "XmlRpcPingModule" type = "CommunityServer.Blogs.Components.XmlRpcPingModule, CommunityServer.Blogs" />
<add name = "WeblogEmailNotificationModule" type = "CommunityServer.Blogs.Components.WeblogEmailNotificationModule, CommunityServer.Blogs" />
<add name = "AutoBlogCreate" type = "CommunityServer.Blogs.Components.AutoBlogCreate, CommunityServer.Blogs" />
<add name = "WeblogCrossPostingModule" type = "CommunityServer.Blogs.Components.WeblogCrossPostingModule, CommunityServer.Blogs" />
<add name = "ImageAttachmentModule" type = "CommunityServer.Blogs.Components.ImageAttachmentModule, CommunityServer.Blogs" />

The order of the above lines is very critical, so make sure you insert in correct spot.  CONGRATULATIONS!!!  You are done.

Posted: Wed, Apr 25 2007 09:42 PM by Bill Bosacker | with no comments
Filed under: ,
CS2007: Code Snipit: Listing Moderated users

Well, I wrote the following snipit to help out a friend and thought that I may as well post it here too.  This snipit uses a few of the features of Chameleon to create a table of all the users in your database.  Unmoderated users will be displayed with a red background as this is only an exercise in the use of the controls:

<table>
 <CSControl:UserList runat="server">
  <HeaderTemplate>
   <tr>
    <td>Display Name</td>
    <td>Moderation Level</td>
    <td>Posts Moderated</td>
   </tr>
  </HeaderTemplate>
  <ItemTemplate>
   <CSControl:ConditionalContent runat="server">
    <ContentConditions Operator="And" runat="server">
     <CSControl:UserPropertyValueComparison ComparisonProperty="ModerationLevel" ComparisonValue="Moderated" Operator="EqualTo" runat="server" />
    </ContentConditions>
    <TrueContentTemplate>
     <tr>
      <CSControl:UserData Property="DisplayName" Tag="td" runat="server" />
      <CSControl:UserData Property="ModerationLevel" Tag="td" runat="server" />
      <CSControl:UserData Property="PostsModerated" Tag="td" runat="server" />
     </tr>
    </TrueContentTemplate>
    <FalseContentTemplate>
     <tr style="background-color: Red;">
      <CSControl:UserData Property="DisplayName" Tag="td" runat="server" />
      <CSControl:UserData Property="ModerationLevel" Tag="td" runat="server" />
      <CSControl:UserData Property="PostsModerated" Tag="td" runat="server" />
     </tr>
    </FalseContentTemplate>
   </CSControl:ConditionalContent>
  </ItemTemplate>
  <RowSeparatorTemplate><br /></RowSeparatorTemplate>
 </CSControl:UserList>
</table>

Posted: Wed, Apr 25 2007 09:35 PM by Bill Bosacker | with no comments
Filed under: ,
CS2007: New Feature: DisableAutomatedVisible

This new feature requires changes to the SDK and allows you to override the protected AutomatedVisible property of any control that derives from the CommunityServer.Controls.WrappedContentBase class.  The AutomatedVisible property is controlled internally by controls with internal rules that control their visibility.

A good example of this is CommunityServer.Blogs.Controls.WeblogPostData control and the LinkTo property.  If the item to link to doesn't exist, instead of just not providing a link the entire control is not rendered.  In some cases you may want to do this, but in others you may not.  The CommentCountBox in blog lists does this and won't display the number of comments or the resource text if comments are disabled and no comments exist.  I thought that this looked sort of funky, thus the reason I created this feature.

To add this feature:

File: CommunityServerControls20/Base/WrappedContentBase.cs:

Around line 155:

Insert the following:

public bool DisableAutomatedVisible
{
 get { return (bool)(ViewState["DisableAutomatedVisible"] ?? false); }
 set { ViewState["DisableAutomatedVisible"] = value; UpdateVisible(); }
}

Around line 232:

Change the following line from:

base.Visible = ((bool)(ViewState["Visible"] ?? true)) && this.AutomatedVisible;

to:

base.Visible = ((bool)(ViewState["Visible"] ?? true)) && (this.AutomatedVisible || this.DisableAutomatedVisible);

Posted: Sun, Apr 22 2007 01:52 PM by Bill Bosacker | with no comments
Filed under: ,
CS2007: BUG: GetSkinPath()

There appears to be a bug in the method CommunityServer.Components.Globals.GetSkinPath().  If CS is running at the root of the Web Site spaces in the skin filepath name are converted to a + (plus), but if CS is running in a Virtual Directory they are correctly changed to %20.  I noticed this when I created a new Theme that has a space in the filepath name.  To correct the issue I made the following change:

File: CommunityServerComponents20/Components/Globals.cs:

Around line 209:

Replace the following line:

return ApplicationPath + "/Themes/" + Globals.UrlEncode(CSContext.Current.User.Theme);

with:

return ApplicationPath + "/Themes/" + Globals.UrlEncode(CSContext.Current.User.Theme).Replace("+", "%20");

CS2007: Inbox notification feature

Hey All,

I'm just getting started with CS 2007, so I thought I'd pick something rather simple.  Even though it is possible to implement this mod without making any changes to the SDK, there is a bug that the last change corrects and does require changing the SDK.  The bug is that unread message count is cached for 3600 seconds (1 hour), when it should only be cached for about 20 seconds at the most.

This mod will modify one of the new theme controls so that the Inbox indicator will turn red and show the number of new messages when you have new messages in your inbox.  If you can't make the SDK changes, then the indicator will only update once every hour.  Here are the changes:

File: CommunityServerWeb20 (Internal)/Themes/default/Common/UserWelcome.ascx:

Insert the following line at line 2:

<%@ Import Namespace="CommunityServer.Components" %>

Replace the following line around line 35:

<CSControl:UserData runat="server" LinkTo="UserPrivateMessages" ResourceName="PrivateMessage_Unread"><LeaderTemplate>| </LeaderTemplate></CSControl:UserData>

with:

<CSControl:ConditionalContent runat="server">
    <ContentConditions>
        <CSControl:CustomCondition runat="server" CustomResult="<%# UserMessages.UnreadMessagesCount(CSContext.Current.User.UserID) > 0 %>" />
    </ContentConditions>
    <LeaderTemplate>| </LeaderTemplate>
    <TrueContentTemplate><CSControl:UserData runat="server" LinkTo="UserPrivateMessages" LinkCssClass="NewPrivateMessage"><ContentTemplate><%# string.Format(ResourceManager.GetString("PrivateMessage_Unread"), UserMessages.UnreadMessagesCount(CSContext.Current.User.UserID)) %></ContentTemplate></CSControl:UserData></TrueContentTemplate>
    <FalseContentTemplate><CSControl:UserData runat="server" LinkTo="UserPrivateMessages" ResourceName="PrivateMessages_Messages" /></FalseContentTemplate>
</CSControl:ConditionalContent>

File: CommunityServerWeb20 (Internal)/Themes/default/Style/Common.css:

After the following (around line 121):

#CommonHeaderUserWelcome
{
    font-size: 80%;
    font-weight: bold;
}

insert:

#CommonHeaderUserWelcome A.NewPrivateMessage, #CommonHeaderUserWelcome A.NewPrivateMessage:VISITED, #CommonHeaderUserWelcome A.NewPrivateMessage:ACTIVE, #CommonHeaderUserWelcome A.NewPrivateMessage:HOVER
{
 color: #FF0000;
}

File: CommunityServerWeb20 (Internal)/Languages/en-US/Resources.xml:

Replace the following 2 lines around line 955:

<resource name = "PrivateMessages_Messages"> Inbox</resource>
<resource name = "PrivateMessage_Unread">Inbox</resource>

with:

<resource name = "PrivateMessages_Messages">Inbox</resource>
<resource name = "PrivateMessage_Unread">Inbox ({0})</resource>

File: CommunityServerComponents20/UserMessages.cs:

NOTE: This is the SDK change.  If you are unable to make this change, the indicator will only update once every 3600 seconds (1 hour).

Replace the following line around line 48:

CSCache.Insert(key, unreadCount, 3600);

with:

CSCache.Insert(key, unreadCount, 20);

Community Server 2007 Released!

Well, Telligent kept it promise and released Community Server 2007 today, but not only did they release the fully compiled version they also released the SDK at the exact same time!  It looks like I'm going to have a busy night upgrading my source control database and learning the new Chameleon abilities.

Enjoy guys...

Posted: Mon, Apr 16 2007 07:40 PM by Bill Bosacker | with no comments
Filed under: ,
Community Server Addons v1.1 for .NET 2.0 is now available

I was asked to turn my BBCode module for blogs into an addon, so I added it to my existing CreateUser addon.  The instructions are included in the download section and the Readme file in the zip.  If you have any questions or issues, let me know.

Community Server Addons v1.1 for .NET 2.0