How to add programmatically users as followers with new SPSecurityEventReceiver in SharePoint 2013

Hello,

Maybe you know that SharePoint 2013 has a lot of new social features, as the "following" concept. In SharePoint 2013, if you have a MySite, you can now follow content or people. Activities from this content will appear in your newsfeed.

For example, in the SharePoint UI, the following button on the upper-right corner of pages enables user to follow a web site :

One of the behavior of this feature is that if you're adding someone as a user in this web site (for example, you're adding a user as a site member), this user is not automatically a follower, because out-of-the-box following a content is a self user action.

If this article, I propose to show you a simple technical to register automatically new users in a web site as followers, with only some lines of code.

Concept

SharePoint 2013 offers two main concepts that you can use to do that :

  • The first one is the extended Social API. There are a lot of new classes that you can use get or set data about social activities. For example, the new SPSocialFollowingManager provides methods to programmatically manage followers.
  • The second one is the new SPSecurityEventReceiver class. This class provide you the possibility to handle event occured while a group is created, a user is inserted in a group, etc. You can handle a lot of kind of security events like: ItemVersionDeleting, GroupAdding, GroupUpdating, GroupDeleting, GroupUserAdding, GroupUserDeleting, RoleDefinitionAdding, RoleDefinitionUpdating, RoleDefinitionDeleting, RoleAssignmentAdding, RoleAssignmentDeleting, InheritanceBreaking, InheritanceRestoring, ItemVersionDeleted, GroupAdded, GroupUpdated, GroupDeleted, GroupUserAdded, GroupUserDeleted, RoleDefinitionAdded, RoleDefinitionUpdated, RoleDefinitionDeleted, RoleAssignmentAdded, RoleAssignmentDeleted, InheritanceBroken, InheritanceRestored

IMPORTANT DISCLAIMER : The following code is compiled as a farm solution. It's may be not the best way and so this code will only work as-is with SharePoint OnPremise. This code used the web application pool identity to insert following information in user personal site. It means that user's personal site must exist, user must be in the user profiles database and that the app pool identity must have full control on personal sites web application.

About the code

The first point is to register a new security event receiver on your web site, to handle group user added and group users deleted event. So I developped a feature receiver to register automatically this event receiver contained in a class called "FollowerSecurityReceiver" :

 public class AutoFollowerEventReceiver : SPFeatureReceiver
{
    private const string eventReceiverUserAddedName = "Automatic follower event user added";
    private const string eventReceiverUserDeletedName = "Automatic follower event user deleted";

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        SPWeb web = properties.Feature.Parent as SPWeb;

        //Adding the event when a user is added
        SPEventReceiverDefinition eventUserAdded = web.EventReceivers.Add();
        eventUserAdded.Name = eventReceiverUserAddedName;
        eventUserAdded.Type = SPEventReceiverType.GroupUserAdded;
        eventUserAdded.Assembly = Assembly.GetExecutingAssembly().FullName;
        eventUserAdded.Class = "AutomaticFollower.FollowerSecurityEventReceiver";
        eventUserAdded.Update();

        //Adding the event when a user is deleted from a group
        SPEventReceiverDefinition eventUserDeleted = web.EventReceivers.Add();
        eventUserDeleted.Name = eventReceiverUserDeletedName;
        eventUserDeleted.Type = SPEventReceiverType.GroupUserDeleted;
        eventUserDeleted.Assembly = Assembly.GetExecutingAssembly().FullName;
        eventUserDeleted.Class = "AutomaticFollower.FollowerSecurityEventReceiver";
        eventUserDeleted.Update();

        web.Update();
    }

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        SPWeb web = properties.Feature.Parent as SPWeb;

        //Remove event receiver for user added
        foreach (SPEventReceiverDefinition eventReceiver in web.EventReceivers)
        {
            if (eventReceiver.Name.Equals(eventReceiverUserAddedName))
            {
                eventReceiver.Delete();
                break;
            }
        }

        //Remove event receiver for user deleted
        foreach (SPEventReceiverDefinition eventReceiver in web.EventReceivers)
        {
            if (eventReceiver.Name.Equals(eventReceiverUserDeletedName))
            {
                eventReceiver.Delete();
                break;
            }
        }
    }
 }

OK, now our feature has registered the event, and we need to use social API to detect added user and to change following settings. By default, you can only automate the "following" parameter for the current user account. So we must use RunWithElevatedPrivileges to use an account with more permissions.

 

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Social;
using Microsoft.Office.Server.Administration;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint.Utilities; 
    
public class FollowerSecurityEventReceiver: SPSecurityEventReceiver
{
    /// <summary>
    /// Handles the event when a user is added in a group
    /// </summary>
    /// <param name="properties"></param>
    public override void GroupUserAdded(SPSecurityEventProperties properties)
    {
        base.GroupUserAdded(properties);

        //Get the targeted user
        SPUser targetUser = properties.Web.AllUsers.GetByID(properties.GroupUserId);

        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            //Get the UserProfil for target user
            SPServiceContext serverContext = SPServiceContext.GetContext(properties.Web.Site);
            UserProfileManager profileManager = new UserProfileManager(serverContext);
            UserProfile profile = profileManager.GetUserProfile(targetUser.LoginName);
            if (profile != null)
            {
                //Inits the social following manager for the profile
                SPSocialFollowingManager manager = new SPSocialFollowingManager(profile);

                //Init the social actor with current web 
                SPSocialActorInfo actorInfo = new SPSocialActorInfo();
                actorInfo.ContentUri = new Uri(properties.WebFullUrl);
                actorInfo.AccountName = targetUser.LoginName;
                actorInfo.ActorType = SPSocialActorType.Site;

                //Follow on this actor
                manager.Follow(actorInfo);
            }

        });
    }

    /// <summary>
    /// Handles the event when the user is deleted from the group
    /// </summary>
    /// <param name="properties"></param>
    public override void GroupUserDeleted(SPSecurityEventProperties properties)
    {
        base.GroupUserDeleted(properties);

        //Get the targeted user
        SPUser targetUser = properties.Web.AllUsers.GetByID(properties.GroupUserId);

        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            //Get the UserProfil for target user
            SPServiceContext serverContext = SPServiceContext.GetContext(properties.Web.Site);
            UserProfileManager profileManager = new UserProfileManager(serverContext);
            UserProfile profile = profileManager.GetUserProfile(targetUser.LoginName);

            if (profile != null)
            {
                //Inits the social following manager for the profile
                SPSocialFollowingManager manager = new SPSocialFollowingManager(profile);

                //Init the social actor with current web 
                SPSocialActorInfo actorInfo = new SPSocialActorInfo();
                actorInfo.ContentUri = new Uri(properties.WebFullUrl);
                actorInfo.AccountName = targetUser.LoginName;
                actorInfo.ActorType = SPSocialActorType.Site;

                //Check if the user is following this web site
                if (manager.IsFollowed(actorInfo))
                {
                    //Stop following 
                    manager.StopFollowing(actorInfo);
                }
            }
        });
    }
}

You can download sample solution bellow (you need Visual Studio 2012 RC and SharePoint 2013 preview kit)

AutomaticFollower.zip