Tuesday, September 04, 2012

An "Unsocial" Bug in Socail NewsGator

NewsGator is a Social Networking Solution for SharePoint environment. Recently our company utilizes NewsGator to make our SharePoint 2010 portal more social and Facebookish. I found an issue related to NewsGator Community API (Social Sites 2010 Suite V2.6.615) today, and missing communication between different dev teams inside NewsGator may be the culprit.

Newsgator heavily uses Feeds and Communities concepts to connect people together and encourages employees participation. Overall those NewsGator features are great. The problem is that, as most third-party components, it's very hard to do some customization on top of NewsGator Components. The NewsGator API and its documentation are so limited that I have to use reflector to figure out some issues to do my work.

Here is the secnario: for security and a few other considerations we don't allow end users to create NewsGator communities directly. Instead, a custom WebPart is built for creating a new Community programmatically so you have full control of that. One of the business requirement is that you can set the NewsGator Community as Public or Private in the custom WebPart.

It sounds straightforward, just setting Community's properties right? But I just couldn't find out the proper way to do that (the formal NewsGator API documentation has less than 20-page with just a few simple code snippets showing how to create Feeds). Thanks to reflector I found there's a SocialContextClient class often used to get/set SocialGroup (Community) inside backend web service calls. So I tried the following code:
    SocialSites.ApplicationServices.SocialContextClient contexClient = 
      new SocialSites.ApplicationServices.SocialContextClient();
    NewsGator.Social.Data.SocialGroup community = contexClient.GetCommunityByName("CommunityName");
    community.PrivacyLevel = NewsGator.Social.Data.SocialGroupPrivacyLevel.Private;
    community.Discoverable = false;
    contexClient.UpdateSocialGroup(community);
The PrivacyLevel and Discoverable properties are responsible for handling the public-visibility, and their values are stored in a SocialGroup table in backend database (NewsGator doesn't use SharePoint lists and has its own database). I could see that the code has successfully updated their values in SocialGroup table, however the created Community is still public. It's very confusing. I checked all possibilities including permission, caching, synchronization, etc. but no luck.

It turns out there’s another method to get the SocialGroup (Community) using SharePointConextManagerBase:
    using (SPSite site = new SPSite(SiteUrl))
    {
        using (SPWeb web = site.OpenWeb())
        {
            SocialGroup community = 
          new NewsGator.Social.Library.Client.SharePointContextManagerBase().GetCommunity(web);
            SocialGroupPrivacyLevel privacyLevel = community.PrivacyLevel;
            bool discoverable = community.Discoverable;
        }
    }
I found that the community’s settings in above method are not the same as what we get from the first method using SocialContextClient. By reflector I traced out that SharePointContextManagerBase actually checks web.AllProperties[NewsGator.Social.Library.SocialGroups.WebKeys.PrivacyLevel] and web.AllProperties[NewsGator.Social.Library.SocialGroups.WebKeys.Discoverable] values to populate the privacy and discoverable values, and it’s not related to any NewsGator backend database.

Apparently different teams from NewsGator had built these two methods with their own purpose. Method SharePointContextManagerBase is used by UI WebParts so updating the backend database by SocialContextClient class won’t have any effect. To workaround this problem simply assign the web’s properties which is checked by SharePointContextManagerBase mthod, then everything works as expected:
    private void UpdateNewsGatorCommunity(SPWeb web, bool isPrivateCommunity)
    {
        if (isPrivateCommunity) // Set NewsGator Community as private
        {
            try
            {
                // Direct value assignment to avoid referecing NewsGator dlls
                web.AllProperties["ng-community-privacy"] = "2";
                web.AllProperties["ng-community-discoverable"] = "False";
                web.Update();
            }
            catch (Exception ex)
            {
                LoggingService.LogError("UpdateNewsGatorCommunity error: " + ex.Message, ex.StackTrace);
            }
        }
    }
It's hacking not an elegant solution and we hope NewsGator could fix this issue in the future.

This is a perfect example of a problem causing by one piece of information defined/stored in multiple places, and reason for that is most likely missing communication between people and teams in a company.