Noteboard to send e-mails to author

The noteboard WebPart that is introduced in SharePoint 2010 is pretty cool since it allows you to share comments and thoughts on any given pag, enabling more social interaction on your site. Yet there are two different versions (or implementations) of the WebPart:

  • The one on the MySite
  • The one you can add to pages yourself

The version on the MySite is a bit different configured as the one you can add yourself. The WebPart that can be added to the page allows you to share comments and ideas on any given page but will not notify anyone once a user adds a comment to a page, while the one on the mysite works a bit different. Whenever someone adds a question to a user’s mysite the noteboard WebPart will send a notification to that person’s mysite. Having such a notification can come in handy thus I would have expected it to be a configuration option to the default WebPart.

Due to unknown reasons that is not the case, having no options to configure a noteboard. However if you would open something to decompile the code you will soon find out that the WebPart added to the mysite is in fact the same WebPart you can add to the page yourself, and will set only one extra property, the EditorEmail with some handy reflection, as the guys at SharePoint Blues prove in a nice post about extending the SocialCommentControl.

Based on those findings, I created a new version of the WebPart that allows you to set the contact e-mail for a noticeboard. The Editor Email can be set using a configuration property in the WebPart itself, or by leaving it blank. If left blank the WebPart will try to resolve the e-mail address based on the author of the current page.

Whenever one of these values are found they are set to the Social Comment WebPart (that will act like the noteboard), and whenever a user adds a comment to the page the configured users email will receive word of that update.

The WebPart is pretty self explanatory and straight forward:

using System.ComponentModel;
using System.Web.UI.WebControls.WebParts;
using Mavention.SharePoint.NoteBoard.WebControls;
using Microsoft.SharePoint;

namespace Mavention.SharePoint.NoteBoard.WebParts.NoteBoard
{
    ///  
    /// WebPart container for the SocialComments control. the functionality in the control is an extension of an OOB WebControl. Since we need it  
    ///     as a WebPart, we use this container. 
    ///  
    [ToolboxItemAttribute(false)]
    public class NoticeBoard : System.Web.UI.WebControls.WebParts.WebPart
    {
        [Category("Mavention Settings")]
        [WebDescription("Enter the ContactEmail adress used for the Social Comment WebPart.")]
        [WebBrowsable(true)]
        [WebDisplayName("Contact E-mail")]
        [Personalizable(PersonalizationScope.Shared)]
        public string ContactEmail { get; set; }

        ///  
        /// Sets up the internal SocialComment WebControl 
        ///  
        protected override void CreateChildControls()
        {
            SocialComments socialComments = new SocialComments();
            
            // Construct the Contact Email, if it is empty lets use the author of the page
            string cEmail = ContactEmail;
            if (string.IsNullOrEmpty(cEmail))
            {
                SPFieldUserValue userValue = new SPFieldUserValue(SPContext.Current.Web, SPContext.Current.ListItem[SPBuiltInFieldId.Author].ToString());
                if (!string.IsNullOrEmpty(userValue.User.Email))
                {
                    cEmail = userValue.User.Email; 
                }
            }
            socialComments.EditorEmail = cEmail;                               
            Controls.Add(socialComments);
        }
    }
}

And for the SocialCommentsControl I made a slightly simplified version

using System;
using System.Web.UI;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.SharePoint.Utilities;

namespace Mavention.SharePoint.NoteBoard.WebControls
{
    /// <summary>
    /// Extension of SocialCommentControl which sends an E-mail whenever a comment is posted.
    /// Code courtsesy of http://www.sharepointblues.com/2011/04/06/extending-the-socialcommentcontrol/ with minor adjustments.
    /// </summary>
    public class SocialComments : SocialCommentControl, ICallbackEventHandler
    {
        /// <summary>
        /// The recipient of the mails.
        /// </summary>
        public string EditorEmail { get; set; }

        /// <summary>
        /// DOM fix 
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            // the DOM is a terrible thing to break
            // http://www.sharepointblues.com/2010/09/28/fix-disabled-page-scrolling-on-navigation-settings/
            Controls.Add(new LiteralControl("</div>"));
        }

        /// <summary>
        /// CallBack Event to actually send the e-mail
        /// </summary>
        /// <param name="eventArgument"></param>
        public void RaiseCallbackEvent(string eventArgument)
        {
            base.RaiseCallbackEvent(eventArgument);

            try
            {
                if (EditorEmail == null)
                {
                    return;
                }

                string currentUser = SPContext.Current.Web.CurrentUser.Name;

                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    SPListItem item = SPContext.Current.ListItem;
                    string url = SPContext.Current.Web.Url + "/" + item.Url;

                    XmlDocument document = new XmlDocument();
                    document.LoadXml(eventArgument);
                    XmlElement documentElement = document.DocumentElement;

                    /*
                        eventArgument when added:
                        <Item  type='Add'>
                            <Title>News</Title>
                            <RTEContents>This is a new comment</RTEContents>
                        </Item>

                         eventArgument when edited
                        <Item type='Edit' 
                        SequenceId='0' 
                        CommentId='144' 
                        CurrentPage='1' >
                        <RTEContents>This is an&amp;#160;edited comment</RTEContents>
                        </Item>
                    */
                    if (documentElement != null)
                    {
                        string oEvent = documentElement.GetAttribute("type");
                        if (oEvent != "Get")
                        {
                            if (oEvent == "Add" || oEvent == "Edit")
                            {
                                var contentElement = (XmlElement)documentElement.SelectSingleNode("./RTEContents");
                                var content = SPHttpUtility.NoEncode(contentElement.InnerText);
                                var subject = string.Format("Comment added: {0}", SPContext.Current.Web.Title);
                                var message = string.Format(@"Content: {0}<br/><br/>By : {1}<br/><br/>Url: {2}", content, currentUser, url);
                                if (!SPUtility.SendEmail(SPContext.Current.Web, true, false, EditorEmail, subject, message))
                                {
                                    // log error sending mail
                                }
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                // Log error
            }
        }
    }
}
There are 7 comments for this article
  1. meiosfem at 12:50

    I've used your code (thanks in advance for sharing) but I keep getting a "The security validation for this page is invalid" everyting I try to post a comment.

    In debug mode, I can see that the fields
    eventArgument when added:
    News
    This is a new comment

    are being filled.

    I've tried to add "AllowUnsafeUpdates = true/false", and also

    base.RaiseCallbackEvent(eventArgument);
    try
    {
    if (Email == null)
    {
    return;
    }

    string currentUser = SPContext.Current.Web.CurrentUser.Name;
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
    using (SPSite site = new SPSite(this.Page.Request.Url.ToString())) //added
    {
    using (SPWeb thisWeb = site.OpenWeb()) //added
    {
    SPListItem item = SPContext.Current.ListItem;
    string url = SPContext.Current.Web.Url + "/" + item.Url;
    XmlDocument document = new XmlDocument();
    document.LoadXml(eventArgument);
    XmlElement documentElement = document.DocumentElement;
    (…)

    but with no success. Can you help?

    Thx

  2. meiosfem at 18:30

    It's a oob enterprisewikipage from shp2010. I know the code you've posted works just fine but for that to happen, either I workaround the SPSecurity.RunWithElevatedPrivileges OR go to the web ap general settings and turn off the "web page security validation"!

    Turning off the "web page security validation" isn't a option (thought the code works just fine).

    I've checked that the formdigest ContentPlaceHolder is on the master page.

    Tried to set SPSecurity.RunWithElevatedPrivileges and then reload the context, no success! (You can see that in the piece of code I've posted earlier).

    I'm very new at this… going to try this solution and see how it goes

    http://blogs.technet.com/b/sharepointdevelopersupport/archive/2013/03/13/using-spsite-and-spweb-objects-with-runwithelevatedprivileges-don-t-cross-the-borders.aspx

  3. meiosfem at 15:29

    I think I got a hint somewhere between your tip about the formdigest and my testing in other pagelayouts.
    It isn't a OOB enterprisewikipage after all (my mistake), it's a redesigned wikipage (changes made to the OOB wiki pagelayout) where it was added a webpart zone (to later insert a noteboard wp) and removed the page rating and categories zone.
    If I try the solution in a default pagelayout for a document library page, for example, the custom noteboard WP works.

    My guess is that, on the top of the pagelayout, something is missing and my gut points to this line:
    ""

    • Albert-Jan Schot at 15:35

      Cool, if you can compare both you should be able to get it working, if not just send me an mail with both pages and ill try and fix it for you.

      • meiosfem at 11:25

        Hi,

        The issue must be related to site template, this solution won't work in publishing templates (publishing site or enterprise wiki). I've even activated every feature available in the "site features", whatever it is, it's melting my brain!

        I've created a new pagelayout with this webpart only, changed the oob pagelayout for the wiki site and added a webpartzone… nothing but a security validation error. If I apply this same pagelayouts in other sites created with a different template (team site, for eg.), they work!

        Any ideias for this behavior? Thanks

        • Albert-Jan Schot at 09:53

          I have seen it working on publishing templates without problems (though on custom pagelayouts), so that is kinda confusing. What buildnumber are you running?

Leave a Reply