Showing posts with label User Profile. Show all posts
Showing posts with label User Profile. Show all posts

Thursday, 26 June 2014

SharePoint Online : Working with People Search and User Profiles


People Search and User Profiles are amongst the popular topics that everyone use in their projects every now and then. With SharePoint 2013, a lot of functionality has been included in the Client API's by Microsoft. If you consider user profiles itself, in SharePoint 2010 you cannot fetch user profiles using client side object model. However, with SharePoint 2013, you have a wide variety of methods that you can use to fetch the user profile information using client object model. The search API is also expanded greatly.

Content Search WebPart is one of the important additions in SharePoint 2013. Using this webpart you can display content that was crawled and added to search index.

To have a complete look at this post refer to the link over here

Cheers,
Geetanjali

SharePoint Online : Export User Profile Properties Using CSOM

With SharePoint 2013, Microsoft has provided the ability to fetch User Profile information client side using CSOM API’s. User Profiles and user profile properties provide information about the SharePoint Users.

The scope of this article is to talk about how we can make use of CSOM API to fetch the user profile information on Office 365 and export profile properties to a csv file.

To read this entire blog post visit the link here.

Sunday, 20 January 2013

Creating Custom Activity Type - Part 3


​Hello Readers,

Welcome back to the Part 3 of this series on creating custom activity type. Just to recap in Part 1 you read about how to get the custom activity type available in your settings page in addition to OOB SharePoint  types. In Part 2 you read about how to get feed related to your custom feed type in your colleagues feed as well as in your feed. So functionality wise we have been able to cover everything. But there is one thing still pending and that is what is happening behind the scenes. When I was trying to implement this feature, I was very anxious in knowing where is the data actually going? So, i explored the content db and found out that it modifies the PROFILE DB and SOCIAL DB. The various tables of interest here are


  1. ActivityPreference : This is the table that acts as a filter. If you remember, when you go to your  newsfeed settings page and try to track down all the activities that you are following then by default you will observe that everything is coming selected. If for any user , all the options are selected for following then there will be NO entry created in the ActivityPreference table. It will create an entry only if any user selects some limited options i.e. why a filter.
  2. ActivityTemplate :  As the name suggests, it is the template for our activity type. We define the Activity Template inside a resource file.The ActivityTemplate table contains the list for all the activity types. Below is the screenshot of this table where if you observe, in the ActivityTemplateId we have the unique ID for our CustomActivityType. If you recall , in Part 1, we had created an ActivityTemplate and ActivityType. Try debugging the code and check the value of these id's and then open up this table in your Profile DB and you will see a record gets created here for your custom activity template.

 
    3. ActivityApplication : If you recall, to start with creating a custom activity type, we had first of all created a custom Activity Application. This information gets stored in the ActivityApplication table in the ProfileDB.


 4.  ActivityType : This table contains the list of all the activity types created. In the table below, if you observe we have our custom Activity Type. If you observe carefully, there is a relation between all these tables that maps one thing to the other like the ActivityTypeId , ApplicationID, ApplicationTemplateId etc.


 5. ActivityEventsConsolidated : This table contains all the events that will appear in the colleagues  newfeed page.


 6. ActivityEventsPublished : This table contains all the events that will appear in the publisher's Recent activities webpart.


So, here I come to the end of the series of the blog posts on custom activity type. I hope that by now you must have got some idea on how to achieve this functionality.


Happy SharePointing !!!!!!

- Geetanjali





Saturday, 19 January 2013

Creating Custom Activity Type - Part 2


​In the previous blog on creating custom activity type Part 1​ , I have shown how to add a custom activity type to appear in the Newsfeed Settings page. In this part I will show how to create activity events so that it starts  to appear in your activity feed. The most important object that you require in order to create an Activity Event is the ActivityManager. But it brings with it some problems. If you look at MSDN , ActivityManager has a constructor


public ActivityManager(
UserProfile userProfile,
SPServiceContext serviceContext
)


Parameters
userProfile : This value must be identical to the UserProfile object that represents the current user.
serviceContext : Default context for this ActivityManager

Here is the problem. The constructor says that the userProfile MUST represent the current user. Now, what will happen if the logged in user is not the administrator and is a normal user with limited permissions?
The user will get an error message stating that the user does not have the required permissions. As a SharePoint developer, we can think of elevating the SPSite object and passing the System Account user to create the ActivityManager object. But it is not simple as it seems to be. Even though you pass the elevated user, still it will pick user from the current context. So how to go about solving this problem. The solution that works over here is to modify the HTTPContext. It seems that the User Profile Service Application depends
upon the HTTPContext . So the workaround to solve this issue is that we need to store the current HTTPContext  in some temporary variable so that later you can set the context back to  the original, impersonate the context, perform your operations and finally set the context back to the original one. Below is the code snippet as to how you can do the same.


HttpContext httpContext = HttpContext.Current;
SPUser user = SPContext.Current.Web.CurrentUser;
string userName = user.LoginName;
try
{
    SPServiceContext currentContext = SPServiceContext.Current;
    HttpRequest request = new HttpRequest("", web.Url, "");
    HttpContext.Current = new HttpContext(request, new HttpResponse(new          StringWriter(CultureInfo.CurrentCulture)));
    HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
             
    WindowsIdentity wi = WindowsIdentity.GetCurrent();
    typeof(WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(wi, adminUser);
    HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);
             
    serviceContext = SPServiceContext.GetContext(HttpContext.Current);
    UserProfileManager pm = new UserProfileManager(serviceContext);
    UserProfile current = null;
             
    if (pm != null)
    {
        SPUser adminUser = web.EnsureUser(adminUser);
        if (user.IsSiteAdmin)
            current = upm.GetUserProfile(adminUser.LoginName);
        HttpContext.Current.Response.Write(current);

    }
    if (current != null)
        actMgr = new Microsoft.Office.Server.ActivityFeed.ActivityManager(current, serviceContext);
             
}
catch (Exception ex)
{
}
finally
{    
    //undo the impersonated httpcontext very much required
    HttpContext.Current = httpContext;
    WindowsIdentity wi = WindowsIdentity.GetCurrent();
    typeof(WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(wi, userName);
    HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);
}

So, if you observe the above code snippet, First store the HTTPContext in a temporary variable httpContext. Second, generate a new context with impersonated user who has the permissions on the User Profile Service Application. Generate the ActivityManager instance using the elevated context. If you  observe now, you will not get any Permission related issue now. Please note that in the finally clause, we are setting the context back to the original one. It is IMPORTANT to set it back to original for obvious reasons. Having successfully generating the ActivityManager instance, you are very near to achieveing the actual motive and i.e. to have a custom feed in your Newsfeed settings page. Next step is to Create an event that will appear in your feed. Below is the sample code snippet to achieve this.


if (actMgr != null)
{
    long aId = actMgr.ActivityApplications["ActivityThemeApplication"].ActivityTypes["ActivityThemeType"].ActivityTypeId;
    if (aId != 0)
    {
        foreach (Colleague colleague in loggedInUser.Colleagues.GetItems())
        {
            CreateEvent(cssFilename, aId, colleague.Profile, actMgr, loggedInUser, themePageURL);
        }
    }
}
public void CreateEvent(string theme, long aId, UserProfile colleagueProfile, Microsoft.Office.Server.ActivityFeed.ActivityManager actMgr, UserProfile loggedInUser,string themePageURL)
{
    try
    {
             
      if (colleagueProfile != null)
      {
          Entity publisher = new MinimalPerson(loggedInUser).CreateEntity(actMgr);
          Entity owner = new MinimalPerson(colleagueProfile).CreateEntity(actMgr);
          ActivityEvent activityEvent = ActivityEvent.CreateActivityEvent(actMgr, aId, owner, publisher);
          activityEvent.Name = "ActivityThemeType";
          activityEvent.ItemPrivacy = (int)Privacy.Public;
          activityEvent.Owner = owner;
          activityEvent.Publisher = publisher;
          Link link = new Link();
          link.Name = "Click here to change your theme." ;
          link.Href = SPContext.Current.Site.Url + themePageURL;
          activityEvent.Link = link;
          activityEvent.Value = theme;
          activityEvent.Commit();
     
       }
     }
     catch (Exception ex)
     {
     }
}



loggedInUser : User Profile of the current logged in user
cssFileName  : It can be anything. In this case, this is the name of the theme that I want to set.
themePageURL : In this case this is the link for my custom page where users can change their themes. It appears in the newsfeed where colleagues can click to change their theme.


In the above code snippet, we are pushing this custom feed in the newsfeed page of all the colleagues of the current logged in user. Publisher is the current logged in user who is changing his theme and Owner is the colleague in whose newsfeed we want the notification to appear. Rest of the code is self-explanatory. The end result is that whenever a person changes his theme then all his colleagues will be notified of this change. In-case you want this to appear in the Recent Activities of the current logged in user who is changing the
theme, then there is a slight modification. In that case you simply need to sent the Owner and Publisher as the same and that is the current logged in user and that is it.



So we can see our custom type in the newsfeed. :)

In the next part I will explain what happens at the backend behind the scenes. Till then keep exploring. :)

- Geetanjali




Creating Custom Activity Type - Part 1


SharePoint 2010 provides us with an excellent feature in the Mysites where we can see our most recent activities using the Recent Activities webpart and the activities of our colleagues by using the NewsFeed webpart. Now the point of interest here is that OOB we can only see feeds for the activity types that SharePoint provides us. The activity feed available OOB collects data from two areas

First is the User Profile changes such as Job Title , Colleague Changes, Birthdays etc and the second is around the social feedback events like tags, new blog posts etc.


We have a scheduled Timer Job which generates new activity events for an individual which are broadcasted to individual's colleagues.

SharePoint 2010 provides two OOB webparts, one shows the consolidated feed in My NewsFeed page which displays all the colleague activity events that I have subscribed to and the other is my published feed that appears in MyProfile page in my Recent Activities.

What if we want to have our own custom type here. I faced this requirement in my current project where I was supposed to show an event in the feed when a user changes a theme. In other words, if my colleague changes some theme , then I should be notified the same in my activity feed and vice versa.


To handle this scenario, we need to create a custom activity type in our newsfeed settings. But how this can be achieved?

I hope by now you must be clear of the exact requirement. To shorten up the long conversation, lets dive directly into the steps that will achieve the desired result.

In this series of blogs I will be explaining how to create a custom activity type, what happens behind the scenes in the Database and what challenges do we face when creating the feed.

To start with, we firstly need to create a custom ActivityApplication for our custom ActivityType.

Create a feature and add an event receiver that will create your custom ActivityApplication on the Feature activation.

SPServiceContext context = SPServiceContext.GetContext(elevatedSite);
UserProfileManager profileManger = new UserProfileManager(context);
UserProfile currentProfile = null;
Microsoft.Office.Server.ActivityFeed.ActivityManager actManager = null;

try
{
      if (profileManger != null)
           currentProfile = profileManger.GetUserProfile(WindowsIdentity.GetCurrent().Name);
}
catch (Exception ex)
{
}
try
{
     if (currentProfile == null)
    {
          if(web.CurrentUser.IsSiteAdmin)
                  currentProfile = profileManger.GetUserProfile(web.CurrentUser.LoginName);
     }
 }
 catch (Exception ex)
 {
  }
 if (currentProfile != null)
    actManager = new Microsoft.Office.Server.ActivityFeed.ActivityManager(currentProfile,context);
if (actManager != null)
{
     ActivityApplication actApplication = EnsureActivityApplication(actManager);
    if (actApplication != null)
    {
         ActivityType customActivityType = actApplication.ActivityTypes["ActivityThemeType"];
        if (customActivityType == null)
        {
             customActivityType = actApplication.ActivityTypes.Create("ActivityThemeType");
             customActivityType.ActivityTypeNameLocStringResourceFile = "CustomActivityType";
             customActivityType.ActivityTypeNameLocStringName = "ActivityName";
             customActivityType.IsPublished = true;
             customActivityType.IsConsolidated = true;
             customActivityType.AllowRollup = true;
             customActivityType.Commit();
             customActivityType.Refresh(true);
         }
         ActivityTemplate customActTemplate = customActivityType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(false)];

        if (customActTemplate == null)
        {
            customActTemplate = customActivityType.ActivityTemplates.Create(false);
            customActTemplate.TitleFormatLocStringResourceFile = "CustomActivityType";
            customActTemplate.TitleFormatLocStringName = "Activity_Created";
            customActTemplate.Commit();
            customActTemplate.Refresh(true);
        }
    }
}
public ActivityApplication EnsureActivityApplication ( Microsoft.Office.Server.ActivityFeed.ActivityManager activityManager)
        {
            ActivityApplication app = null;
            if (activityManager != null)
            {
                //Check to see that the current user has permissions to access the social data 
                if (activityManager.PrepareToAllowSchemaChanges())
                {
                    app = activityManager.ActivityApplications["ActivityThemeApplication"];
                    if (app == null)
                    {
                        app = activityManager.ActivityApplications.Create("ActivityThemeApplication");
                        app.Commit();
                        app.Refresh(true);
                    }
                    return app;
                }
                else
                {
                    try
                    {
                        //The process user doesn’t have access to profiles service as manage social data role 
                        return activityManager.ActivityApplications["ActivityThemeApplication"];
                    }
                    catch (ActivityFeedPermissionDeniedException ex)
                    {
                     }
                }
            }
            return app;
        }

In the above code snippet , we are first fetching the UserProfile and then creating an instance of ActivityManager. After that we check whether ActivityApplication exists or not and if it does not exist then we create a new ActivityApplication for our custom activity type. After that we create a custom activity type and custom activity template. You need to make sure that you are using the correct permissions to perform the above operation so as to avoid Access Denied issue.

You can also see the Resource files that I have been using above. It basically helps you in setting the name and message for your custom Activity Type.




Now, a custom activity type with the name Theme Change will appear in our NewsFeed Settings page and the message that will appear will be as {Publisher} changed theme to {Value} where the {Publisher} will be replaced by the colleague account name and in {Value} we will populate the name of the Theme.

So, in this way, we can create a new custom Activity type in our newsfeed setting page. But this is not enough. We still need to implement the logic to create an event for the same so that it can be made available in the newsfeed.

Stay Tuned for the next part where I will explain you the logic to create activity events. :)


Missing SitePages in Personal Site


Lately I faced and issue while working with Personal Sites. My requirement was to deploy a page in personal sites everytime a personal site gets created. So, the quick solution that came to my mind was to deploy it using feature stapling, and everytime the personal site gets provisioned for somebody, the feature will get activated and my page will get deployed to the SitePages library in the personal site that gets created. To my utter surprise, there was no SitePages library in my personal site though it was present in the MySite host. Then I found out that "Wiki Page Home Page" feature , which activates by default for Team Sites ,do not get activated by default for certain site templates, including the personal sites. Therefore , personal sites do not contain SitePages library by default. In-case we want to create SitePages library in personal sites then in our feature activation we need to write the following line of code that ensures creation of the SitePages library.

SPList list = web.Lists.EnsureSitePagesLibrary();


And thats it. This will create SitePages library for a non team site. :)

Cheers,
Geetanjali