The fact is that Andy, my work mate, came on Friday with the idea of detecting a user, query it by getting the properties of the USER PROFILE in a modal form. Good challenge isn’t it?, he is a good man so I always I accept his challenges. I start studying the documentation for the SP.js library and after hours trying to find the way to access to custom user properties I couldn't find anything. You can only get the name, email etc… basic stuff but if you want something else, forget it.
My limitation was extreme, I didn’t have access to the Sharepoint.Client.dll, JavaScript or the Server Model, so I decided to implement the Sharepoint Web Services against JavaScript and use both platforms JavaScript (SP.js) and Web Services (/_vti_bin/UserProfileService.asmx with the method GetUserPropertyByAccountName()).
I have to admit it was hard work, but at the end I managed to make it work.
In the code I am going to post are three buttons which call 3 functions:
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetUsers.aspx.cs" Inherits="netsourcecodeJavaScript.Layouts.netsourcecodeJavaScript.GetUsers" DynamicMasterPageFile="~masterurl/default.master" %>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<% #if SOME_UNDEFINED_CONSTANT %>
<script type="text/javascript" src="/_layouts/SP.debug.js" ></script>
<script type="text/ecmascript" src="/_layouts/SP.js" ></script>
<script type="text/ecmascript" src="/_layouts/SP.Core.js" ></script>
<script type="text/ecmascript" src="/_layouts/SP.Runtime.Debug.js" ></script>
<% #endif %>
<script language="ecmascript" type="text/ecmascript">
//## Activate this function if you want to load the script at the very beginig
//ExecuteOrDelayUntilScriptLoaded(DisplayList, "sp.js");
//## Variables
var context = null;
var web = null;
var currentUser = null;
var collListItems = null;
var username = null;
var loginname = null;
var isgettinglist = false;
//## 1
//## This function gets the login name and display it in a MessageBox
function DisplayUser() {
isgettinglist = false;
GetUserData();
}
//## 2
//## This function displays the values from the list
function DisplayList() {
isgettinglist = true;
GetUserData();
}
//## 3
//## This function says hello.
function SayHello() {
alert('Hellow!');
}
//## Getting the user
function GetUserData() {
//## Getting the context
context = new SP.ClientContext.get_current();
//## Getting the web
web = context.get_web();
//## Getting the current user
currentUser = web.get_currentUser();
//## Load the query
currentUser.retrieve();
context.load(web);
//## Execute the query Async
context.executeQueryAsync(Function.createDelegate(this, this.onSuccessMethod), Function.createDelegate(this, this.onFailureMethod));
}
//## SUCCESS FOR USER EVENT
function onSuccessMethod(sender, args) {
//## Setting the object to get the current user...again...
var userObject = web.get_currentUser();
//## Adding the user into a Variable
username = userObject.get_title();
loginname = userObject.get_loginName();
if (isgettinglist == false) {
alert('User name:' + username + '\n Login Name:' + loginname);
}
if (isgettinglist == true) {
//## Getting the results from the list
var department = GetPropertyFromUserProfile("http://ecmdemo.panint.com/lms/_vti_bin/UserProfileService.asmx", "Department", loginname);
var title = GetPropertyFromUserProfile("http://ecmdemo.panint.com/lms/_vti_bin/UserProfileService.asmx", "Title", loginname);
GetListByName(loginname,department,title);
}
}
//## FAILURE FOR USER EVENT
function onFailureMethod(sender, args) {
alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());
}
//## It gets the property froma user profile
function GetPropertyFromUserProfile(url,name,value)
{
var responsefromwebservice = null;
var parameters = new SOAPClientParameters();
parameters.add("acountName", value);
parameters.add("propertyName", name);
//## SYNC MODE
var response = SOAPClient.invoke(url, "GetUserPropertyByAccountName", parameters, false);
//#############
//## ASYNC MODE
//SOAPClient.invoke("http://ecmdemo.panint.com/lms/_vti_bin/UserProfileService.asmx", "GetUserPropertyByAccountName", pl, true, GetDepartMentFromUserProfile_callBack);
//function GetDepartMentFromUserProfile_callBack(r)
//{alert(r);}
//alert(response.Values[0].Value);
//#############
if (response != null) responsefromwebservice = response.Values[0].Value;
return responsefromwebservice;
}
//## It gets the number of seats quering the login, department and title
function GetListByName(username,department,title) {
//## Get the context again
context = new SP.ClientContext.get_current();
//## Get the list
var list = context.get_site().get_rootWeb().get_lists().getByTitle('Shared Documents');
//## Builds a CAMEL querty to return items
var query = new SP.CamlQuery();
//query.set_viewXml('<View><Query><Where><Eq><FieldRef Name="Author"/><Value Type="User">' + username + '</Value></Eq></Where></Query><ViewFields><FieldRef Name="Title"/><FieldRef Name="FileLeafRef"/></ViewFields></View>');
query.set_viewXml('<Query> <Where> <And> <Contains><FieldRef Name="Grade" /> <Value Type="Text">' + title + '</Value> </Contains> <And><Contains><FieldRef Name="Group" /><Value Type="Text">' + department + '</Value></Contains><And> <Geq> <FieldRef Name="Start" /> <Value IncludeTimeValue="TRUE" Type="DateTime">' + GetDateTimeNowForCAMLQuery() + '</Value> </Geq> <Gt><FieldRef Name="Remaining_x0020_Seats" /> <Value Type="Number">0</Value> </Gt> </And></And> </And></Where></Query>');
//## Geting the items
this.collListItems = list.getItems(query);
context.load(collListItems);
//## Execute the query Async
context.executeQueryAsync(Function.createDelegate(this, this.GetListByNameSuccessFunctionEvent), Function.createDelegate(this, this.GetListByNameFailFunctionEvent));
}
//## SUCCESS FOR LIST EVENT
function GetListByNameSuccessFunctionEvent() {
//## Do something useful like loop through your returned list items and output in a variable
var listItemEnumerator = this.collListItems.getEnumerator();
var strHtml = "";
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
strHtml += oListItem.get_item('Remaining_x0020_Seats').toString();
}
return strHtml;
//alert(strHtml);
}
//## FAIL FOR USER EVENT
function GetListByNameFailFunctionEvent() { alert('Request fail'); }
//###################################################################
//###################################################################
//################ U T I L I T I E S ################################
//###################################################################
//###################################################################
function GetDateTimeNowForCAMLQuery()
{
//## FORMAT 2011-09-16T16:15:18z
var currentTime = new Date()
return currentTime.getFullYear()+'-'+currentTime.getMonth()+'-'+currentTime.getDay()+'T'+currentTime.getHours()+':'+currentTime.getMinutes()+':'+currentTime.getSeconds()+'z';
}
function SOAPClientParameters() {
var _pl = new Array();
this.add = function (name, value) {
_pl[name] = value;
return this;
}
this.toXml = function () {
var xml = "";
for (var p in _pl) {
switch (typeof (_pl[p])) {
case "string":
case "number":
case "boolean":
case "object":
xml += "<" + p + ">" + SOAPClientParameters._serialize(_pl[p]) + "</" + p + ">";
break;
default:
break;
}
}
return xml;
}
}
SOAPClientParameters._serialize = function (o) {
var s = "";
switch (typeof (o)) {
case "string":
s += o.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); break;
case "number":
case "boolean":
s += o.toString(); break;
case "object":
// Date
if (o.constructor.toString().indexOf("function Date()") > -1) {
var year = o.getFullYear().toString();
var month = (o.getMonth() + 1).toString(); month = (month.length == 1) ? "0" + month : month;
var date = o.getDate().toString(); date = (date.length == 1) ? "0" + date : date;
var hours = o.getHours().toString(); hours = (hours.length == 1) ? "0" + hours : hours;
var minutes = o.getMinutes().toString(); minutes = (minutes.length == 1) ? "0" + minutes : minutes;
var seconds = o.getSeconds().toString(); seconds = (seconds.length == 1) ? "0" + seconds : seconds;
var milliseconds = o.getMilliseconds().toString();
var tzminutes = Math.abs(o.getTimezoneOffset());
var tzhours = 0;
while (tzminutes >= 60) {
tzhours++;
tzminutes -= 60;
}
tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
}
// Array
else if (o.constructor.toString().indexOf("function Array()") > -1) {
for (var p in o) {
if (!isNaN(p)) // linear array
{
(/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
var type = RegExp.$1;
switch (type) {
case "":
type = typeof (o[p]);
case "String":
type = "string"; break;
case "Number":
type = "int"; break;
case "Boolean":
type = "bool"; break;
case "Date":
type = "DateTime"; break;
}
s += "<" + type + ">" + SOAPClientParameters._serialize(o[p]) + "</" + type + ">"
}
else // associative array
s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">"
}
}
// Object or custom function
else
for (var p in o)
s += "<" + p + ">" + SOAPClientParameters._serialize(o[p]) + "</" + p + ">";
break;
default:
break; // throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
}
return s;
}
function SOAPClient() { }
SOAPClient.username = null;
SOAPClient.password = null;
SOAPClient.invoke = function (url, method, parameters, async, callback) {
if (async)
SOAPClient._loadWsdl(url, method, parameters, async, callback);
else
return SOAPClient._loadWsdl(url, method, parameters, async, callback);
}
// private: wsdl cache
SOAPClient_cacheWsdl = new Array();
// private: invoke async
SOAPClient._loadWsdl = function (url, method, parameters, async, callback) {
// load from cache?
var wsdl = SOAPClient_cacheWsdl[url];
if (wsdl + "" != "" && wsdl + "" != "undefined")
return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
// get wsdl
var xmlHttp = SOAPClient._getXmlHttp();
xmlHttp.open("GET", url + "?wsdl", async);
if (async) {
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4)
SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
}
}
xmlHttp.send(null);
if (!async)
return SOAPClient._onLoadWsdl(url, method, parameters, async, callback, xmlHttp);
}
SOAPClient._onLoadWsdl = function (url, method, parameters, async, callback, req) {
var wsdl = req.responseXML;
SOAPClient_cacheWsdl[url] = wsdl; // save a copy in cache
return SOAPClient._sendSoapRequest(url, method, parameters, async, callback, wsdl);
}
SOAPClient._sendSoapRequest = function (url, method, parameters, async, callback, wsdl) {
// get namespace
var ns = (wsdl.documentElement.attributes["targetNamespace"] + "" == "undefined") ? wsdl.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : wsdl.documentElement.attributes["targetNamespace"].value;
// build SOAP request
var sr =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<" + method + " xmlns=\"" + ns + "\">" +
parameters.toXml() +
"</" + method + "></soap:Body></soap:Envelope>";
// send request
var xmlHttp = SOAPClient._getXmlHttp();
if (SOAPClient.userName && SOAPClient.password) {
xmlHttp.open("POST", url, async, SOAPClient.userName, SOAPClient.password);
// Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
xmlHttp.setRequestHeader("Authorization", "Basic " + SOAPClient._toBase64(SOAPClient.userName + ":" + SOAPClient.password));
}
else
xmlHttp.open("POST", url, async);
var soapaction = ((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + method;
xmlHttp.setRequestHeader("SOAPAction", soapaction);
xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
if (async) {
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4)
SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
}
}
xmlHttp.send(sr);
if (!async)
return SOAPClient._onSendSoapRequest(method, async, callback, wsdl, xmlHttp);
}
SOAPClient._onSendSoapRequest = function (method, async, callback, wsdl, req) {
var o = null;
var nd = SOAPClient._getElementsByTagName(req.responseXML, method + "Result");
if (nd.length == 0)
nd = SOAPClient._getElementsByTagName(req.responseXML, "return"); // PHP web Service?
if (nd.length == 0) {
if (req.responseXML.getElementsByTagName("faultcode").length > 0) {
if (async || callback)
o = new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
else
throw new Error(500, req.responseXML.getElementsByTagName("faultstring")[0].childNodes[0].nodeValue);
}
}
else
o = SOAPClient._soapresult2object(nd[0], wsdl);
if (callback)
callback(o, req.responseXML);
if (!async)
return o;
}
SOAPClient._soapresult2object = function (node, wsdl) {
var wsdlTypes = SOAPClient._getTypesFromWsdl(wsdl);
return SOAPClient._node2object(node, wsdlTypes);
}
SOAPClient._node2object = function (node, wsdlTypes) {
// null node
if (node == null)
return null;
// text node
if (node.nodeType == 3 || node.nodeType == 4)
return SOAPClient._extractValue(node, wsdlTypes);
// leaf node
if (node.childNodes.length == 1 && (node.childNodes[0].nodeType == 3 || node.childNodes[0].nodeType == 4))
return SOAPClient._node2object(node.childNodes[0], wsdlTypes);
var isarray = SOAPClient._getTypeFromWsdl(node.nodeName, wsdlTypes).toLowerCase().indexOf("arrayof") != -1;
// object node
if (!isarray) {
var obj = null;
if (node.hasChildNodes())
obj = new Object();
for (var i = 0; i < node.childNodes.length; i++) {
var p = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
obj[node.childNodes[i].nodeName] = p;
}
return obj;
}
// list node
else {
// create node ref
var l = new Array();
for (var i = 0; i < node.childNodes.length; i++)
l[l.length] = SOAPClient._node2object(node.childNodes[i], wsdlTypes);
return l;
}
return null;
}
SOAPClient._extractValue = function (node, wsdlTypes) {
var value = node.nodeValue;
switch (SOAPClient._getTypeFromWsdl(node.parentNode.nodeName, wsdlTypes).toLowerCase()) {
default:
case "s:string":
return (value != null) ? value + "" : "";
case "s:boolean":
return value + "" == "true";
case "s:int":
case "s:long":
return (value != null) ? parseInt(value + "", 10) : 0;
case "s:double":
return (value != null) ? parseFloat(value + "") : 0;
case "s:datetime":
if (value == null)
return null;
else {
value = value + "";
value = value.substring(0, (value.lastIndexOf(".") == -1 ? value.length : value.lastIndexOf(".")));
value = value.replace(/T/gi, " ");
value = value.replace(/-/gi, "/");
var d = new Date();
d.setTime(Date.parse(value));
return d;
}
}
}
SOAPClient._getTypesFromWsdl = function (wsdl) {
var wsdlTypes = new Array();
// IE
var ell = wsdl.getElementsByTagName("s:element");
var useNamedItem = true;
// MOZ
if (ell.length == 0) {
ell = wsdl.getElementsByTagName("element");
useNamedItem = false;
}
for (var i = 0; i < ell.length; i++) {
if (useNamedItem) {
if (ell[i].attributes.getNamedItem("name") != null && ell[i].attributes.getNamedItem("type") != null)
wsdlTypes[ell[i].attributes.getNamedItem("name").nodeValue] = ell[i].attributes.getNamedItem("type").nodeValue;
}
else {
if (ell[i].attributes["name"] != null && ell[i].attributes["type"] != null)
wsdlTypes[ell[i].attributes["name"].value] = ell[i].attributes["type"].value;
}
}
return wsdlTypes;
}
SOAPClient._getTypeFromWsdl = function (elementname, wsdlTypes) {
var type = wsdlTypes[elementname] + "";
return (type == "undefined") ? "" : type;
}
// private: utils
SOAPClient._getElementsByTagName = function (document, tagName) {
try {
// trying to get node omitting any namespaces (latest versions of MSXML.XMLDocument)
return document.selectNodes(".//*[local-name()=\"" + tagName + "\"]");
}
catch (ex) { }
// old XML parser support
return document.getElementsByTagName(tagName);
}
// private: xmlhttp factory
SOAPClient._getXmlHttp = function () {
try {
if (window.XMLHttpRequest) {
var req = new XMLHttpRequest();
// some versions of Moz do not support the readyState property and the onreadystate event so we patch it!
if (req.readyState == null) {
req.readyState = 1;
req.addEventListener("load",
function () {
req.readyState = 4;
if (typeof req.onreadystatechange == "function")
req.onreadystatechange();
},
false);
}
return req;
}
if (window.ActiveXObject)
return new ActiveXObject(SOAPClient._getXmlHttpProgID());
}
catch (ex) { }
throw new Error("Your browser does not support XmlHttp objects");
}
SOAPClient._getXmlHttpProgID = function () {
if (SOAPClient._getXmlHttpProgID.progid)
return SOAPClient._getXmlHttpProgID.progid;
var progids = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
var o;
for (var i = 0; i < progids.length; i++) {
try {
o = new ActiveXObject(progids[i]);
return SOAPClient._getXmlHttpProgID.progid = progids[i];
}
catch (ex) { };
}
throw new Error("Could not find an installed XML parser");
}
SOAPClient._toBase64 = function (input) {
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
keyStr.charAt(enc3) + keyStr.charAt(enc4);
} while (i < input.length);
return output;
}
</script>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<SharePoint:FormDigest ID="FormDigest1" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Get User" />
<asp:Button ID="Button2" runat="server" Text="Query List" />
<asp:Button ID="Button3" runat="server" Text="Say Hello" />
</asp:Content>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Application Page
</asp:Content>
<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
My Application Page
</asp:Content>
Conclusion: As you can see you can achieve almost everything with the native webservices. Unfortunately Intellisense doesn't work properly for JavaScript in Visual Studio 2010…so it is a nightmare to do something with it.