Posting on SharePoint 2013 newsfeed on behalf of someone else

It is a common requirement in the enterprise social scenarios, to post on to SharePoint newsfeed on behalf on someone else. Those reasons are mainly in the domain of the social governance, or implementing internal procedures. Just think of automatic admin posts to the site feeds, in the case of important breaches of internal procedures. Or, think of a common practice of posting as bot user on personal feed – let’s say, there is a bot CRM user, which automatically posts to it’s newsfeed all important sales events which are coming from the CRM system.

SharePoint 2013 client object model does not give us an opportunity to post on behalf of someone else. For this purpose, we need to use SharePoint 2013 server object model, which is all but good documented (at least at the moment).

For this purpose, we will make an use of few classes from the “Microsoft.Office.Server.Social” namespace.

SPSocialFeedManager is the class which contains most important methods for manipulating feeds for any user. SPSocialPostCreationData contains information about a single post. SPSocialDataItem contains information about social actors associated with a social post.  With SPSocialAttachment, we can add attachments to social posts. And if you would like to specify your own application as a poster to the newsfeed (something like “Posted by my cool app”), you will make a use of the SPSocialLink class.

Since all this is happening in an user context, we will need to use UserProfileManager from the Microsoft.Office.Server.UserProfiles namespace.

For this to work, it is important to remember the feed structure – I was writing about it in one of my pervious posts:

Feed

Any feed – personal or site feed – contains a number of threads. Each thread contains an array of social actors. It is very important that those actors are found in array in that particular order, in which they appear in the thread. That order is the only way for SharePoint 2013 feed to know which social actor comes at which position inside the thread. Each thread contains at least one root post, and any number of replies. Post – root or reply – contain info about the author, likes, post body, and eventual attachments.

So let’s look how does it work in practice.

Please take a look at the code below, the whole thing is explained in the inline comments (that’s where it belongs, anyway Winking smile)

using (SPSite site = new SPSite(contextSiteName))
{
    
    string username = "sharedove\someuser";
    
    SPServiceContext context = SPServiceContext.GetContext(site);

    UserProfileManager profileManager = new UserProfileManager(context);

    if (profileManager.UserExists(username))
    {
        UserProfile userProfile = profileManager.GetUserProfile(username);
    } else {
        // Oops. User that you want to post on behalf of, can not be found
        // You would do something really clever here in production.
        return; 
    }

    //get the Social Feed Manager in the context of the requested user
    SPSocialFeedManager feedManager = new SPSocialFeedManager(userProfile, context);

		//Create SPSocialPostCreationData object for a new social post
    SPSocialPostCreationData postCreationData = new SPSocialPostCreationData();
		
    //set the body of the post. Note the arguments, and their order. 
    postCreationData.ContentText = "Hello, the user {0} is going to be mentioned here. We will also have a link {1}, and a tag {2}";

    //now we need to add the social actors (SPSocialDataItem), in the same order we have the arguments in the post body:
    
    //let's first mention an user
    SPSocialDataItem socialDataMentionItem = new SPSocialDataItem();
    socialDataMentionItem.ItemType = SPSocialDataItemType.User;
    socialDataMentionItem.AccountName = "sharedove\mentionedUser";

    //Add mention to the PostCreationDataContentItems
    Array.Resize(ref postCreationData.ContentItems, postCreationData.ContentItems.Length + 1);
    postCreationData.ContentItems[postCreationData.ContentItems - 1] = socialDataMentionItem;

    
    //Next, add a link as SPSocialDataItem to the postCreationData
    SPSocialDataItem socialDataLinkItem = new SPSocialDataItem();
    socialDataLinkItem.ItemType = SPSocialDataItemType.Link;
    socialDataLinkItem.Text = "Adis Jugo Blog";
    socialDataLinkItem.Uri = new Uri("http://blog.sharedove.com/adisjugo/");

    //Add social link item to the PostCreationDataContentItems
    Array.Resize(ref postCreationData.ContentItems, postCreationData.ContentItems.Length + 1);
    postCreationData.ContentItems[postCreationData.ContentItems - 1] = socialDataLinkItem;
    
    //As the last (third) social item, add a tag
    string myTag="#blogpost";
    
    //Now, since the hashtags are actually stored in the TermStore (Managed Metadata Service), in order this to work,
    //we need to add our tag there:
    SPSecurity.RunWithElevatedPrivileges(delegate
    {
        using (SPSite elevatedSiteCollection = new SPSite(site.ID))
        {
            TermSet settingsTermSet = null;
            
            //create a taxonomy session
            TaxonomySession session = new TaxonomySession(elevatedSiteCollection, true);

            // obtain the term store
            TermStore store = session.DefaultSiteCollectionTermStore;

            //get the groups
            GroupCollection groups = store.Groups;

            // get the System taxonomy group
            Group settingsGroup = store.Groups.Where(x => x.Name == "System").FirstOrDefault();

						//get the Hashtags termset
            hashTermSet = settingsGroup.TermSets.Where(x => x.Name == "Hashtags").FirstOrDefault();

            //and now, try to get our tag from the termset
            hashtagTerm = hashTermSet.Terms.Where(x => x.Name == myTag).FirstOrDefault();
            
            //or create it if it does not exist
            if (hashtagTerm == null)
            {
                hashtagTerm = hashTermSet.CreateTerm(termName, hashTermSet.TermStore.DefaultLanguage);

                hashtagTerm.IsAvailableForTagging = true;

                // commit it all
                hashTermSet.TermStore.CommitAll();
            }

        }
     });
    

     // Now, when we have a hashtag term, let's add it to the social post
     SPSocialDataItem socialDataTagItem = new SPSocialDataItem();
     socialDataTagItem.ItemType = SPSocialDataItemType.Tag;
     socialDataTagItem.Text = tag;
     socialDataTagItem.TagGuid = hashtagTerm.Id;

     //Add the tag to the PostCreationDataContentItems
     Array.Resize(ref postCreationData.ContentItems, postCreationData.ContentItems.Length + 1);
     postCreationData.ContentItems[postCreationData.ContentItems - 1] = socialDataTagItem;

     //On the end, add an attachemt to the social post
     string attachment = "http://mysite/photo.jpg";
     SPSocialAttachment statusAttachment = new SPSocialAttachment();
     
     //Now, determine the attachment type. SharePoint will display on different ways videos, photos, and images attachments.
     if (attachment.ToUpper().EndsWith("JPG") || attachment.ToUpper().EndsWith("JPEG") || attachment.ToUpper().EndsWith("PNG") || attachment.ToUpper().EndsWith("GIF"))
     {
         statusAttachment.AttachmentKind = SPSocialAttachmentKind.Image;
     }
     else if (attachment.ToUpper().EndsWith("WMV") || attachment.ToUpper().EndsWith("MP4") || attachment.ToUpper().EndsWith("AVI") || attachment.ToUpper().EndsWith("MPEG"))
     {
         statusAttachment.AttachmentKind = SPSocialAttachmentKind.Video;
     }
     else
     {
         statusAttachment.AttachmentKind = SPSocialAttachmentKind.Document;
     }

     statusAttachment.Uri = new Uri(attachment);
     statusAttachment.Name = "Look here";
     postCreationData.Attachment = statusAttachment;


     //set the posting "app" (actually, anything can go here);
     postCreationData.Source = new SPSocialLink() { Uri = new Uri("http://blog.sharedove.com"), Text = "ShareDove cool social app"};

     //create the post in feed of the user, in whose context we have created SPFeedManager. 
     //That's why we leave null here. 
     feedManager.CreatePost(null, postCreationData);
     
     //For the site feed, we would put SharePoint site in the CreatePost:
     feedManager.CreatePost("http://sharepointserver/sites/somesite/", postCreationData);
 
}