Home
Our Work
Services
Small Business Intranet
Samples
Training
SharePoint
Hosting
    

dbWeb > Blogs > Brandt Fuchs > Categories
Use a MOSS Web Service to Obtain User Data
Here is what I believe to be the most userful web service that MOSS provides out of the box, the UserProfileService.
 
 
This web service can be utilized to obtain a large set of information about the current user.  Below is a list of the value names that you can return by calling this web service.
 
UserProfile_GUID
AccountName
FirstName
LastName
PreferredName
WorkPhone
Office
Department
Title
Manager
AboutMe
PersonalSpace
PictureURL
UserName
QuickLinks
WebSite
PublicSiteRedirect
SPS-Dotted-line
SPS-Peers
SPS-Responsibility
SPS-Skills
SPS-PastProjects
SPS-Interests
SPS-School
SPS-SipAddress
SPS-Birthday
SPS-MySiteUpgrade
SPS-DontSuggestList
SPS-ProxyAddresses
SPS-HireDate
SPS-LastColleagueAdded
SPS-OWAUrl
SPS-ResourceAccountName
SPS-MasterAccountName
Assistant
WorkEmail
CellPhone
Fax
HomePhone
 
I obtained this list by calling the web service into an XSLT web part in SPD and displaying all Names.
 
These properties are all obtained from the Shared Services Provider's User Profile directory that is synced with AD.  Often I find companies will have AD sparsely populated with very few of these fields actually containing data.  But the more data that is populated about each user, the more that we can leverage the user profiles.
 
For instance, we can call this web service from InfoPath and have it return the current user and their manager, which could then be used in turn in a workflow to route the form for approval.
 
We could also create a linked source in SharePoint Designer that links this web service with a list of PTO data.  We could then filter the PTO data to only show employees taking PTO for my office based on that value from the web service.  This provides for a much more focused view of PTO data by only showing the employees in the same office as the current user.
Displaying Attachments in Multiple Item Xslt Data View Web Part
So I had posted an item previously about displaying attachments in a data view web part.  My previous post only works when using a single item view. When working with a multiple item view some modifications to the code are needed.
 
At first I tried this code
 
<SharePoint:AttachmentsField ControlMode="Display" ItemId="{@ID}" EnableViewState="true" FieldName="Attachments" runat="server"/>
 
I though that adding the ItemID attribute would be sufficient, however this proved not to be the case.  The issue I experienced is that this code works in a single item view, but in a multiple item view it selects first item's ID as all item's 'ItemID' attribute on the SharePoint:AttachmentsField control.
 
The result is that if the first item has an attachment, that attachment is displayed for all items.  Likewise if the first item has no attachments, all items display no attachment.

It is obvious to me that the SharePoint:AttachmentField control is not receiving the correct ID for each item, but rather all are receiving the first item's ID.  I can't tell why that is though.

I managed to figure this one out, although I must admit the solution supprised me.  What I did was add the following code right before my SharePoint:AttachmentField control

<SharePoint:AttachmentButton ControlMode="Edit" Enabled="true" ItemId="{@ID}" runat="server" Visible="false"/>

So the code that displays attachments on a multiple item view is as follows.

<SharePoint:AttachmentButton ControlMode="Edit" Enabled="true" ItemId="{@ID}" runat="server" Visible="false"/><SharePoint:AttachmentsField ControlMode="Display" ItemId="{@ID}" EnableViewState="true" FieldName="Attachments" runat="server"/>

Printer Friendly Pages
I often hear, 'can I get a printer friendly display of the data within sharepoint?'  I've seen a feature around that add a menu button to list toolbars - here.  I went down another route to accomplish this, and I'll admit it's not the most elegant solution as it could be packaged into a feature.  It does however allow users to print the content on any page attached to the master page rather than just lists with a toolbar.
 
This will allow you, from any page that is attached to the master page, to hide all but the main content area so that you can print a page without the extra content using up all the ink in your printer. Of course this is not as elegant as a feature that would deploy across all sites, but it works and if some body wants to wrap it up into a feature, go right ahead.
 
Insert the following divs onto the masterpage, wherever you would like to see the buttons to change views from a non printer-friendly view to a printer-friendly view.
  
<div id="printbutton"><asp:Button CssClass="ms-vb" runat="server" UseSubmitBehavior="false" OnClientClick="javascript:PrinterFriendly();return false;" Text="Print-Friendly" id="Button1" CausesValidation="False" EnableViewState="False" /></div>
 

<div id="nonprintbutton" style="display:none"><asp:Button CssClass="ms-vb" runat="server" UseSubmitBehavior="false" OnClientClick="javascript:NonPrinterFriendly();return false;" Text="Non Print-Friendly" id="Button2" CausesValidation="False" EnableViewState="False" /></div>

Insert the following javascript in the head tag of the masterpage. (replace content this color with the IDs of the elements you want to hide/show)
 

<script type="text/javascript" language="javascript">

function PrinterFriendly(){

                document.getElementById('id of area you want to hide').style.display="none";

                document.getElementById('id of area you want to hide').style.display="none";

                document.getElementById('id of area you want to hide').style.display="none";

                document.getElementById('id of body or outermost element to fit within a page width').style.width="7.5in";

                document.getElementById('nonprintbutton').style.display="";

                document.getElementById('printbutton').style.display="none";

}

function NonPrinterFriendly(){

                document.getElementById('id of area you want to show').style.display="";

                document.getElementById('id of area you want to show').style.display="";

                document.getElementById('id of area you want to show').style.display="";

                document.getElementById('id of body or outermost element to be fullscreen').style.width="100%";

                document.getElementById('printbutton').style.display="";

                document.getElementById('nonprintbutton').style.display="none";

}

</script>

You will have to go through the master page and add a few IDs to the areas that you want to hide/show so that you can reference these areas with the above javascript. You could use this code to hide and show any part of the site that you might want to print.
Windows SharePoint Services 4.0 - XSLT Views
According to Microsoft http://support.microsoft.com/default.aspx?scid=kb;EN-US;956450 the next version of SharePoint is going to use XSLT web parts instead of the current default list views.  If you've read even a few of my posts then you know that I love working with XSLT, so this is good news for me!
GoGo Gadget-Lack-of-Documentation
I was doing a bit of digging through the most informative source of SharePoint documentation - my fellow SharePoint professional's blogs - and I discovered something that could have serious consequences for many organizations.  Take a look at Dave Wollerman's blog post entitled Huge MOSS Workflow Issue... What is Mircrosoft Thinking!!!!.  Here is the scoop in short; workflow history is purged after 60 days!  That's alright, it's no big deal if you don't care about storing your information for more than 2 months.  For those of us that live in the real world though, this could be very detrimental, especially for organizations that get audited.
 
I have been working very extensively with an international asset management firm for over a year now, and they get audited regularly.  Luckily for them, the way I build my workflows does not rely on any information being stored within the workflow history.
 
Rather than logging events in the workflow, and assigning tasks that are associated with the item that the workflow was initiated from, I have always opted for a simpler approach.  Now when I say simpler I mean from an end user perspective, not an initial setup/design perspective. 
 
I don't like assigning tasks to users through a workflow because the e-mails that users receive from a newly created task are just too cluttered.  There is a handful of links that take users everywhere except you tube, and in my experience this results in too much confusion to be productive.
 
I also don't like navigating into the workflow details screen to see what has happened.
 
My approach to designing workflows that are simple, easy to understand, and effective, revolves around one concept - centralization.  Rather than having a list item, a workflow, and many associated tasks, all to accomplish one process, I send out custom e-mails from the workflow that link to custom XSLT data form web parts that allow users to update hidden fields on the same list item from which the workflow was initiated.  The end result is that all auditable information is stored in hidden fields on the list item.  These fields can then be displayed on a custom XSLT data view web part as an audit page.  This way when 60 days go by and your workflow goes down the drain, all of the important information is still available via the list item.
Auto-Populate a People or Groups Field With the Current User Name
***Update:  This code does not work in Firefox***
 
I'll start this post with a disclamer that this code is not my own, I found different parts of the following code in different blog posts around the internet, but could not find this complete solution in one coherent post, so I decided to put it up myself.  I found the beginning of the code here.
 
Place the following code just inside the PlaceHolderMain tag of a newform.aspx page, or on a page with any custom form on it, and it should automatically populate a people or groups field with the name of the currently logged on user.
 
<script type="text/javascript">
_spBodyOnLoadFunctionNames.push("fillDefaultValues");
 
function fillDefaultValues() {
  var qs = location.search.substring(1, location.search.length);
  var args = qs.split("&");
  var vals = new Object(getUserDisplayName());
 
  var assignedToInput = getTagFromIdentifierAndTitle("div", "", "People Picker");
  assignedToInput.innerHTML = vals;
  for (var i=0; i < args.length; i++) {
    var nameVal = args[i].split("=");
    var temp = unescape(nameVal[1]).split('+');
    nameVal[1] = temp.join(' ');
    vals[nameVal[0]] = nameVal[1];
  } 
}
 
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
  var len = identifier.length;
  var tags = document.getElementsByTagName(tagName);
  for (var i=0; i < tags.length; i++) {
    var tempString = tags[i].id;
    if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {
      return tags[i];
    }
  }
  return null;
}
function getUserDisplayName() {
 var tags = document.getElementsByTagName('a');
 for (var i=0; i < tags.length; i++) {
  if(tags[i].innerText.substr(0,7) == 'Welcome') {
   return tags[i].innerText.substr(8,tags[i].innerText.length);
  }
 }
}
</script>
Web Part Page Error
Sometimes when opening a SharePoint web part page you will see an error that references the ability to go the Web Part Page maintenance.  This allows you to remove any web parts that you think might be causing the error.  This is very useful, if it comes up.  I just recently came across a scenario where ther erroneous web part was closed on the page (which means you can only see it in SPD, and that no error occurs in the browser).  When trying to access the page in SPD I get an error that say I cant open the page and should try the web part page maintenance.  The downside is that this error message does not give you a link to that page. 
 
So here is how to get to the web parts page maintenance for any page.  Simply navigate to the page with the issue and ad a query string 'contents=1'.  For example navigating to http://intranet/default.aspx?contents=1 would take me to the web parts page maintenance for the home page.
 
A Tribute to SharePoint Designer Workflows
Right off the bat I'm sure that I am rubbing some Visual Studio developers the wrong way, but hear me out. 
 
SharePoint Designer is an amazingly powerful tool, and while products produced in SPD may not be as robust as solutions developed in VS, there are almost always adequate in getting the job done.
 
Let me start by explaining some of the core limitations of SPD workflows in contranst to VS workflows.
 
SharePoint designer workflows cannot…
 
1)      Run steps in parallel – They can only run in sequence.
2)      Run loops – although you can make loops happen, they are a bit finicky and not something standard.
3)      Update a people or groups field on a list item – this is a standard action of SPD workflows that does not work properly.
4)      Pause until date – this is also a standard action of SPD workflows that does not work properly.
5)      Run under an impersonated account – SPD workflows always run under the identity of the user who initiated the workflow.
6)      Access lists and libraries on other sites - SPD Workflows are deployed to a single list on a single site, although they can access and act off of other information in lists on the same site.
7)     Be easily deployed to similar lists/libraries on other sites - This is possible, it is a matter of editing some of the XML code files that correspond to the workflow, as well as updating any references to lists in the workflow itself.
 
That may seem like a long list of roadblocks, but in my experience, more often than not these are null issues.  Now that I've gotten that out of the way, let's focus on how we can use SPD workflows to our advantage.
 
1)      SPD workflows can be created by anyone with an understanding of simple if/else/then logic.
2)      SPD workflows can be created in a fraction of the time of the time that it takes to develop a VS workflow.  Let's face it, given that the creation of workflows often involves taking a physical process and making it electronic, the process itself is usually changed along with the change in medium.  This fact, more so than not, results in an iterative workflow creation process that looks something like this;
  1. set requirements
  2. develop
  3. test
  4. demo
  5. receive new requirements
  6. rinse
  7. repeat

So when you have to redevelop a workflow X number of times until the result is satisfactory, the time saved in SPD vs VS is exponential!
3)      As we all know saving time is saving money, and why would you want to pay an expensive developer to work 5 times longer than an employee that can utilize the SPD workflows?

For those who might still be skeptical, here is a sampling of generic workflows I've created in SPD.

Vacation requests that routes to a mangaer for approval and also tracks the number of days an employee has taken and has left.

Expense Authorizations that require X levels of approval.

Help desk requests that route to the qualified member of the support staff based upon the nature of the request.

Tasks - # of days overdue
You know what would be really beneficial?  The ability to use the Today function within a SharePoint calculated column.  This would give us the ability to create a calculated column named Days Overdue that would look something like (Today - Due Date); This could be used in a view of open tasks and if the result was positive then the task would be overdue by that number of days.  Unfortunately you cannot use the Today function in a calculated column.
 
To get around this limitation of SharePoint I utilized some JavaScript along with a Data View Web Part.
 
As of right now I am posting this as a reminder to myself.  The SharePoint environment where I created this solution is currently down, and as soon as it is back up I will post the JavaScript and XSLT code needed to display the difference between dates.
Totals in an XSLT Data View Web Part
I always hated that when you convert a standard SharePoint Web Part, that shows totals for columns (count, sum, etc.), into an XSLT dataview web part within SharePoint Designer, the totals disappear.  This never made much sense to me, as every other part of the view is translated into the appropriate XSLT code.  So this post will discuss how to put those totals back in.
 
When you group by a field in XSLT, the header for each group boils down to displaying
 
<xsl:value-of select="$fieldtitle"/>:<xsl:value-of select="$fieldvalue" />  = Day:N or Day:N+1 in the image at the bottom of this post.
 
Keep in mind that this is not the exact code that is in the part.  There is other code that I have stripped out just to keep it simple.
 
In my example I am grouping by the Day field.  All I wanted to do is count the number of items for each group, but you could also sum numeric fields if you so wish (as well do a number of other calculations).  To accomplish this I implemented this code
 
- <xsl:value-of select="count(/dsQueryResponse/Rows/Row[@Day = $fieldvalue])"/> Items
 
So I am counting (for each header) the number of items where the list item value for the Day field equals the current group header value.
 
The final result is shown below
Totals in XSLT Web Part
1 - 10 Next