User Profile Services via Client Object Model

I was recently thinking through ways to help drive adoption of an intranet and engage users to explore the various capabilities of the system. One thought was to alert users if they have not supplied a profile photo, or a short bio in their MySite. Sure we could do this with web services, but I thought I’d figure out how to do it with the client object model with ECMAScript. After a lot of searching, I kept finding blog posts that said I was out of luck and there was no way to query User Profiles via the client object model. At a high level, that assessment is correct, but what we can do is query the user info list of the current site.

When I first started this, none of the test users in my lab had a profile picture, so I added one and found that my script kept returning a null object instead of my picture. The hidden Easter egg here is that the site’s user info list isn’t updated in real time. If you head over to Central Administration -> Monitoring -> Review job definitions and dig down the list you’ll find a job called “User Profile Service Application – User Profile to SharePoint Full Synchronization“. This timer job will execute every hour and synchronize the properties of your User Profile Services to the site user info list, so the picture that was set on the MySite is now accessible via the user info list.

First things first, we need to find out the ID of the user that’s currently viewing the page (this is the physical numerical record of the user in the site’s user info list, not the login username). Credit to Mike Oryszak (@next_connect) and his blog post on using the status bar to display active workflows for getting me in the right direction on this piece. We’ll start out by grabbing the current web context and fire off that query. If the query is successful in executing, it’ll call the onUserSuccessMethod function.

var context = null;
var web = null;
var curUser = null;

function getUser() {
	context = new SP.ClientContext.get_current();
	web = context.get_web();
	curUser = web.get_currentUser();
	curUser.retrieve();
	context.load(web);
	context.executeQueryAsync(Function.createDelegate(this, this.onUserSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
}

Now that we have our context we’ll create a variable called user and assign it to the current user object, and call our loadProfile function to do the profile query.

function onUserSuccessMethod(sender, args) {
	var user = web.get_currentUser();
	loadProfile();
}

The loadProfile function defines the user info list, builds the CAML query to get the record for the current user, and fires that query off. If the query is successful in executing, it’ll call the onProfileSuccessMethod function.

function loadProfile() {
	context = SP.ClientContext.get_current();
	web = context.get_web();
	userInfoList = web.get_siteUserInfoList();
	camlQuery = new SP.CamlQuery();
	camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + curUser.get_id() + '</Value></Eq></Where></Query><RowLimit>1</RowLimit></View>');
	this.listItems = userInfoList.getItems(camlQuery);
	context.load(listItems);
	context.executeQueryAsync(Function.createDelegate(this, this.onProfileSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
}

Now that we have the result set from our query (in the form of a listItems object), all we need to do is grab the first (and only item), this will be on index 0 in the array, and analyze the picture field to see if there’s a value there or not. If there is a picture object, we’ll grab the Url to it and save it in a new variable (pictureURL) just in case we want it. If there is no picture object, we’ll fire off a call to SP.UI.Status to add a new status bar telling the user they don’t have a photo, with a link to their profile where they can add one.

function onProfileSuccessMethod(sender, args) {
	var item = listItems.itemAt(0);
	var picture = item.get_item('Picture');
	if (picture) {
		var pictureURL = picture.get_url();
	} else {
		noPicture = SP.UI.Status.addStatus('Profile Photo', 'You have not added a profile photo to your account. <a href=\'http://mysites/person.aspx\'>Add one now!</a>');
		SP.UI.Status.setStatusPriColor(noPicture, 'blue');
	}
}

You’ll notice that both getUser() and loadProfile() have references to an onFailureMethod function, in the event that our query fails. This will be a simple function to just alert our error.

function onFailureMethod(sender, args) {
	alert('Error: ' + args.get_message() + '\n' + args.get_stackTrace());
}

Now that we’ve got all of our functions written, all we need is a simple call to our getUser() function (after the core SharePoint JavaScript has loaded, of course).

ExecuteOrDelayUntilScriptLoaded(getUser, "sp.js");

Putting it all together:

My “Michael Greene” account has a user profile image, so we just see normal SharePoint with no profile photo alerts.

My “Setup Account” account does not have a profile image, so SharePoint prompts us that we should add a photo.

Due to the fact that we have to wait on the timer job to run and update the user info list with the new photo, it’s possible that the user could add a photo then still see the prompt telling them they haven’t. In a true application of this, we could add a condition to check the Modified time of the user info list record to see if the record has been “updated” in the last hour, to avoid that false positive. Only if the record has been updated within the hour and has no photo, should we alert the user.

Enhancing SharePoint 2010 for the iPad (SPSAusTX 2012)

Despite being marketed as an entertainment device rather than a mobile platform for business, the iPad continues to gain traction as a mobile device for the next generation business user. For some organizations, the rich user interaction and usability afforded by the iPad is a compelling reason to work towards cross-platform capability or iPad specific versions of line-of-business systems. In this session we’ll review custom iPad specific enhancements for SharePoint 2010, including changes to the user interface based on the orientation of the device.

Presented at SharePoint Saturday Austin, TX (January 21, 2012).

Demonstration Video:

Enhancing SharePoint 2010 for the iPad (SPSVB 2012)

Despite being marketed as an entertainment device rather than a mobile platform for business, the iPad continues to gain traction as a mobile device for the next generation business user. For some organizations, the rich user interaction and usability afforded by the iPad is a compelling reason to work towards cross-platform capability or iPad specific versions of line-of-business systems. In this session we’ll review custom iPad specific enhancements for SharePoint 2010, including changes to the user interface based on the orientation of the device.

Presented at SharePoint Saturday Virginia Beach (January 7, 2012).

SharePoint Saturday Tampa

For anyone interested, here’s the slide deck that I presented at SharePoint Saturday Tampa on June 11, 2011 on Enhancing SharePoint 2010 for the iPad. You can also download a copy of the slides here.

White Paper: Branding SharePoint 2010

My recent white paper titled Branding SharePoint 2010 provides an overview of the concepts, components and process behind a complete branding effort-from requirements definition and prototyping to development and deployment.

Intellinet

TRISPUG Presentation (2/1/2011)

Despite being marketed as an entertainment device rather than a mobile platform for business, the iPad continues to gain traction as a mobile device for the next generation business user. For some organizations, the rich user interaction and usability afforded by the iPad is a compelling reason to work towards cross-platform capability or iPad specific versions of line-of-business systems. In this session we’ll review custom iPad specific enhancements for SharePoint 2010, including changes to the user interface based on the orientation of the device.

Above is a copy of the charts that I presented at the Triangle SharePoint User Group meeting on February 1, 2011. I’ve included the separate YouTube video containing a hands on demonstration of the CSS approach after slide 18.

White Paper: SP2010 Enhancements for the iPad

My recent white paper titled SharePoint 2010 Enhancements for the Apple iPad includes topics on orientation detection, orientation-aware content, and cross-platform embedded video solutions.

Intellinet

Enhancing the SharePoint 2010 UI: Scripted Orientation Aware Content

In my previous post we looked at enhancing the SharePoint 2010 UI through CSS based orientation detection. In this post, we will take it one step further and use some client side script to detect orientation and output content accordingly.

The CSS approach utilizes orientation aware style sheets which are loaded based on the appropriate orientation of the device (in this case an iPad). While this approach is simple to implement, it’s not necessarily the most robust solution or the most scalable solution. The CSS approach is best suited to deployment with your site’s branded master page, when orientation detection is a big part of your design. What if you only wanted it on one or two pages of your site, if you don’t have access to deploy a new master page, or if you want more advanced orientation detection?

Read more →