Tuesday, February 23, 2010

HOW TO Get all SharePoint Groups that a User belongs to

Bamboo Solutions - Access your network file shares from SharePoint

SharePoint File Share Library - Seems like a pretty useful tool from Bamboo Solutions. You can use this to point at existing network shares and sync them ‘continuously’ or on a ‘schedule.’

http://app.tech.pentontech.com/e/es.aspx?s=1481&e=1267&elq=9c677d46e18e4b9e8f72ce4ab9d89b95

 

Monday, February 22, 2010

SharePoint URL Cheat sheet

Here are links that list the URLs to various SharePoint pages such as ‘View All Site Content’ and 'Web Part Maintenance'
http://www.heathersolomon.com/blog/articles/1116.aspx
http://boris.gomiunik.net/2008/03/navigating-through-sharepoint-site-using-url/

Saturday, February 20, 2010

HOW TO Delete Content Types in SharePoint

I found these great blog posts that show how to delete Content Types in SharePoint. If you have worked with InfoPath and/or SharePoint, it is very likely that you have run into this ridiculously useless error message:
Content Type in Use

http://blog.tylerholmes.com/2008/02/deleting-content-types-in-sharepoint.html
http://suguk.org/blogs/the_moss-pit/archive/2008/10/31/14853.aspx

Now you can get rid of those pesky Content Types that you no longer need.
Thanks Tyler Holmes! Your post is worth its value in gold.

Thursday, February 11, 2010

HOW TO Customize SharePoint Search Results page using XSLT

Here is a link to an excellent resource that shows how you can customize the SharePoint Search Results page using XSLT in SharePoint Designer.

http://www.zimmergren.net/archive/2007/10/28/moss-2007-customize-the-search-result-using-xslt-part-3-customize-using-sharepoint-designer-2007.aspx

 

SharePoint Query String Parameters and Web Part Maintenance Page

Here is an excellent resource that lists the various query string parameters that can be used in SharePoint Site URLs.

Thanks to Daniel McPherson's Blog post for this info:
SharePoint Query Strings


My favorite is ?Contents=1. This will display the SharePoint 'Web Part Maintenance Page' which can be useful when you have a Web Part that is causing an error. You can then close the Web Part in this Maintenance Page.

For example:

http://teamwork.company.com/sites/yoursite/default.aspx?contents=1

This usually redirects to something like this:
http://teamwork.company.com/sites/yoursite/_layouts/spcontnt.aspx?&url=%2fsites%2fyoursite%2fdefault.aspx

Searching content in PDF documents and displaying PDF icon

Here are some useful resources related to configuring SharePoint to search content 'within' PDF documents and to display the Adobe PDF icon next to the results in the Search Results page.

Adobe IFilter 9 download link

Adobe PDF Icon Link

Configuring PDF IFilter for MS SharePoint 2007

SharePoint BreakRoleInheritance() and ResetRoleInheritance() code sample

Here is some sample code that shows how to use the SPListItem.BreakRoleInheritance() and SPListItem.ResetRoleInheritance() methods to implement Item Level Permissions and Restore List Level Permissions respectively. I implemented these methods in Event Handler code that was attached to a SharePoint Document Library.


using System;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;

namespace KiranK.SharePointSite.EventHandlers
{
public class DownloadManager : SPItemEventReceiver
{
public override void ItemAdding(SPItemEventProperties properties)
{

try
{
this.DisableEventFiring();

//Get Security Level and Select Users/Groups values
string strSecLevel = properties.AfterProperties["Security_x0020_Level"].ToString().Trim();
string strUserOrGroups = properties.AfterProperties["Select_x0020_Users_x0020_or_x002"].ToString().Trim();

//If Specific User is selected, but Users/Groups is blank, we need to display an error message and prevent saving of the Item.
if (strSecLevel == "Specific User" & (strUserOrGroups == "" | strUserOrGroups == string.Empty))
{
properties.ErrorMessage = "The 'Select Users or Groups' field cannot be blank, if you select 'Specific User' as the Security Level for this Document." + "
" + "Please click on the Back button in the browser and select User(s) and/or Group(s).";
properties.Cancel = true;
}
}
catch (Exception ex)
{
throw ex;
}

finally
{
this.EnableEventFiring();
}


}

public override void ItemAdded(SPItemEventProperties properties)
{



try
{
//This prevents the Event Receiver from running twice
this.DisableEventFiring();

//Collect the values entered by the user in the newly created Item in the Download Manager List

//Retrieve the properties associated with the newly created Item in the Download Manager List here
SPListItem dwdMgrItem = properties.ListItem;

//Get the Security Level value selected here
string strSecLevel = dwdMgrItem["Security Level"].ToString().Trim();



//Check if Security Level = Specific User
//If True, then we need to call the function that breaks role inhertitance from the Parent List, and implements Item Level permissions
if (strSecLevel == "Specific User")
{

BreakRoleInheritance(properties);
}

}

catch (Exception ex)
{

throw ex;
}

finally
{
this.EnableEventFiring();
}


}

public void BreakRoleInheritance(SPItemEventProperties properties)
{

//Get the Users or Groups selected here
//Multiple Users are stored like this -> User or Group selected = 173;#John Doe;#175;#Jane Doe;#172;#John Pongo
//Single User is stored like this -> 173;#John Doe
//Multiple values are separated by semicolons
//string strUserGroupSelected = dwdMgrItem["Select Users or Groups"].ToString().Trim();


//Initialize a SPWeb and SPListItem objects
SPWeb elevatedWeb = null;
SPListItem elevatedListItem = null;

try
{

//Run this code block with Elevated Privileges
//This is because Site Users will NOT have FULL CONTROL in SharePoint
//They will have CONTRIBUTE access in SharePoint and this access level
//does not allow you to break role inheritance.
//However, SPSite and SPWeb objects obtained via the Run With Elevated Privileges method
//will allow these Users to perform this operation.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//This will be a POST request. Call ValidateFormDigest to ensure that this is a valid update and not a cross-site scripting attack
//Refer: http://hristopavlov.wordpress.com/2008/05/21/what-you-need-to-know-about-allowunsafeupdates-part-2/
SPUtility.ValidateFormDigest();

//Get a handle to the SPSite object inside the Elevated code block
using (SPSite elevatedSite = new SPSite(properties.SiteId))
{

//Get a handle to the SPWeb object inside the Elevated code block
using (elevatedWeb = elevatedSite.OpenWeb())
{

//Get the following error if AllowUnsafeUpdates is NOT set to True
//Microsoft.SharePoint.SPException: The security validation for this page is invalid.
elevatedWeb.AllowUnsafeUpdates = true;

//Get a handle to the List Item using the elevated SPWeb object
elevatedListItem = elevatedWeb.GetListItem(properties.ListItem.Url);

//Get all the Users in the Web
//SPUserCollection users = elevatedWeb.AllUsers;
SPUserCollection users = elevatedWeb.SiteUsers;

//Get all the Cross-site Groups for the Site Collection
//SPGroupCollection groups = web.Groups;
SPGroupCollection groups = elevatedWeb.SiteGroups;

//Call BreakRoleInheritance. false indicates that current role assignments in the Parent List will NOT be copied to this Item.
elevatedListItem.BreakRoleInheritance(false);

//Update the List Item
elevatedListItem.Update();



//Call function that will set Item Level Permissions.The user or users will be assigned Contributor permissions to this Item
elevatedListItem = SetItemLevelPermissions(elevatedWeb, elevatedListItem, SPRoleType.Contributor, users, groups);

//Update the Item again
elevatedListItem.Update();

//Set AllowUnsafeUpdates back to false
elevatedWeb.AllowUnsafeUpdates = false;

} //using elevatedWeb
} //using elevateSite

}); //closing for SPSecurity.RunWithElevatedPrivileges


}
catch (Exception ex)
{

throw ex;
}

finally
{
//Dispose SPWeb object
if (elevatedWeb != null)
elevatedWeb.Dispose();

////Dispose SPSite object
//if (elevatedSite != null)
// elevatedSite.Dispose();
}

}

public SPListItem SetItemLevelPermissions(SPWeb setSPWeb, SPListItem setListItem, SPRoleType setRoleType, SPUserCollection users, SPGroupCollection groups)
{
try
{
//Create an ArrayList that will store the User or Group IDs
ArrayList alUserGroup = new ArrayList();

//Get the Users or Groups selected here
//Multiple Users are stored like this -> User or Group selected = 173;#John Doe;#175;#Jane Doe;#172;#John Pongo
//Single User is stored like this -> 173;#John Doe
//Multiple values are separated by semicolons
string strUserGroupSelected = setListItem["Select Users or Groups"].ToString().Trim();

//Split the multiple values and store them in an Array
string[] strArrUserGroup = Regex.Split(strUserGroupSelected, ";#");

//Iterate through the Array and store the User or Group IDs in the ArrayList
foreach (string strUserGroupValue in strArrUserGroup)
{
//Check if the value is a number
//If True, this is a User or Group ID
if (IsWholeNumber(strUserGroupValue))
{
//Add User or Group IDs to the ArrayList
alUserGroup.Add(Int32.Parse(strUserGroupValue));
}
}

//Set the Role Definition to Contribute here...
SPRoleDefinition roleDefinition = setSPWeb.RoleDefinitions.GetByType(setRoleType);

//Iterate through the ArrayList
//Get the User or Group ID
foreach (int intUserGroupID in alUserGroup)
{
//determine if ID is user or group
Boolean isGroup = false;
foreach (SPGroup testGroup in setSPWeb.SiteGroups)
{
if (testGroup.ID == intUserGroupID)
{
isGroup = true;
}
}
if (isGroup == false) //this is a User ID
{

SPUser userToAdd = users.GetByID(intUserGroupID);

SPRoleAssignment userRoleAssignment = new SPRoleAssignment(userToAdd);
userRoleAssignment.RoleDefinitionBindings.Add(roleDefinition);
setListItem.RoleAssignments.Add(userRoleAssignment);
}
else //this is a Group ID
{

SPGroup groupToAdd = groups.GetByID(intUserGroupID);

SPRoleAssignment groupRoleAssignment = new SPRoleAssignment(groupToAdd);
groupRoleAssignment.RoleDefinitionBindings.Add(roleDefinition);
setListItem.RoleAssignments.Add(groupRoleAssignment);
}
}

//Add 'SP Site Administrators' group to the Item Permissions List

SPGroup oSiteAdminGroup = setSPWeb.SiteGroups["SP Site Administrators"];
SPRoleAssignment siteAdminGroupRoleAssignment = new SPRoleAssignment(oSiteAdminGroup);
siteAdminGroupRoleAssignment.RoleDefinitionBindings.Add(roleDefinition);
setListItem.RoleAssignments.Add(siteAdminGroupRoleAssignment);

return setListItem;
}
catch (Exception ex)
{

throw ex;
}

finally
{
//Do nothing
}
}

public override void ItemUpdating(SPItemEventProperties properties)
{

try
{
this.DisableEventFiring();

//Get Security Level and Select Users/Groups values
string strSecLevel = properties.AfterProperties["Security_x0020_Level"].ToString().Trim();
string strUserOrGroups = properties.AfterProperties["Select_x0020_Users_x0020_or_x002"].ToString().Trim();

//If Specific User is selected, but Users/Groups is blank, we need to display an error message and prevent saving of the Item.
if (strSecLevel == "Specific User" & (strUserOrGroups == "" | strUserOrGroups == string.Empty))
{
properties.ErrorMessage = "The 'Select Users or Groups' field cannot be blank, if you select 'Specific User' as the Security Level for this Document." + "
" + "Please click on the Back button in the browser and select User(s) and/or Group(s).";
properties.Cancel = true;
}
}
catch (Exception ex)
{

throw ex;
}

finally
{
this.EnableEventFiring();
}

}

public override void ItemUpdated(SPItemEventProperties properties)
{



try
{
this.DisableEventFiring();
string strSecLevel = properties.AfterProperties["Security_x0020_Level"].ToString().Trim();

if (strSecLevel != "Specific User")
{

ResetRoleInheritance(properties);
}

}

catch (Exception ex)
{

throw ex;
}

finally
{
this.EnableEventFiring();
}

}

private void ResetRoleInheritance(SPItemEventProperties properties)
{
//Initialize a SPWeb and SPListItem objects
SPWeb elevatedWeb = null;
SPListItem elevatedListItem = null;

try
{

//Run this code block with Elevated Privileges
//This is because Site Users will NOT have FULL CONTROL in SharePoint
//They will have CONTRIBUTE access in SharePoint and this access level
//does not allow you to reset role inheritance.
//However, SPSite and SPWeb objects obtained via the Run With Elevated Privileges method
//will allow these Users to perform this operation.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//This will be a POST request. Call ValidateFormDigest to ensure that this is a valid update and not a cross-site scripting attack
//Refer: http://hristopavlov.wordpress.com/2008/05/21/what-you-need-to-know-about-allowunsafeupdates-part-2/
SPUtility.ValidateFormDigest();

//Get a handle to the SPSite object inside the Elevated code block
using (SPSite elevatedSite = new SPSite(properties.SiteId))
{

//Get a handle to the SPWeb object inside the Elevated code block
using (elevatedWeb = elevatedSite.OpenWeb())
{

//Get the following error if AllowUnsafeUpdates is NOT set to True
//Microsoft.SharePoint.SPException: The security validation for this page is invalid.
elevatedWeb.AllowUnsafeUpdates = true;

//Get a handle to the List Item using the elevated SPWeb object
elevatedListItem = elevatedWeb.GetListItem(properties.ListItem.Url);

//Remove Users and Groups from the People Picker field in this Item
elevatedListItem["Select Users or Groups"] = string.Empty;

//Call ResetRoleInheritance.
//This will remove Item Level Permissions and restore List level Permissions.
//In other words, the Permissions assigned to the List will be inherited by the Item.
elevatedListItem.ResetRoleInheritance();

//Update the List Item
elevatedListItem.Update();

//Set AllowUnsafeUpdates back to false
elevatedWeb.AllowUnsafeUpdates = false;

} //using elevatedWeb
} //using elevateSite

}); //closing for SPSecurity.RunWithElevatedPrivileges



}

catch (Exception ex)
{

throw ex;
}

finally
{
//Dispose SPWeb object
if (elevatedWeb != null)
elevatedWeb.Dispose();

////Dispose SPSite object
//if (elevatedSite != null)
// elevatedSite.Dispose();
}
}



//This method checks if the string that is passed is a valid whole number or not
public bool IsWholeNumber(String strNumber)
{
Regex objNotWholePattern = new Regex("[^0-9]");
return !objNotWholePattern.IsMatch(strNumber);
}
}
}

Friday, February 5, 2010

How To Resolve 'object required' error in Custom Edit Form

If you get the JavaScript 'object required' error when you attempt to attach a file in your custom Edit Form, it is likely because of the 'idAttachmentsRow{generate-id()}' value in the 'id=' attribute in the table row (tr) tag.

Change the value to to 'idAttachmentsRow' (i..e. remove the {generate-id()} part), and the error will not occur.

Your updated code should look like this:

<tr id="idAttachmentsRow"> <td nowrap="true" valign="top" class="ms-formlabel" width="20%"> <SharePoint:FieldLabel ControlMode="Edit" FieldName="Attachments" runat="server"/> </td> <td valign="top" class="ms-formbody" width="80%"> <SharePoint:FormField runat="server" id="AttachmentsField{$Pos}" ControlMode="Edit" FieldName="Attachments" __designer:bind="{ddwrt:DataBind('u',concat('AttachmentsField',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Attachments')}"/> <script></script> </td> </tr>

Credit:
http://support.microsoft.com/kb/953271

Thursday, February 4, 2010

SharePoint Custom List Form with 'Attach File' link working

The 'Attach File' link does not work in custom List Forms. This is a known issue as evidenced in the discussion threads below:

http://sharepoint07.wordpress.com/2008/02/05/customize-the-newformaspx/

http://social.msdn.microsoft.com/forums/en-US/sharepointcustomization/thread/d3ebb776-f80d-46aa-9cb9-38f90652d001/ (this thread also contains some alternate approaches to resolving this issue)

Listed below are the 2 MS Support articles related to this issue:
http://support.microsoft.com/kb/953271

http://support.microsoft.com/kb/960311

In my case, I had to sort of combine the resolution steps provided in the 2 MS Support articles above. You will see this in my "12 Steps" below.

First and foremost, you need to ensure that you have this configuration in your environment:

1. SP2 (with latest cumulative updates) for SharePoint
2. SP1 for SharePoint Designer (SPD) 2007
3. Install KB960311

I got the steps listed below to work only in the above configuration.

If you have SP2 for SharePoint Designer installed, then you need to remove SPD 2007, re-install it. When you re-install SPD 2007, SP1 will be included in it. You don't have to install SP1 for SPD separately. Then you need to install KB960311. Thanks to my astute Manager, Yoshio Kurtz, for this tip regarding SPD configuration. I would not have been able to resolve this issue without Yoshio's help.

If you have SPD 2007 + SP2, and then try to install KB960311, you will get the following error:

The expected version of the product was not found on the system.

KB960311 does NOT work with SPD that has SP2. It works with SPD that has SP1.


"12 Steps "

1. Created a new List in SharePoint.

2. Ensured that the ‘Attach File’ link works.

3. Ensured that I can view the ‘correct’ Web Part properties window for the default ListFormWebPart in SPD.

4. Added a ‘Person or Group’ column to the List in SharePoint.

5. Ensured that the ‘Attach File’ link works.

6. Created the custom New Form (this gets rendered in a DataFormWebPart) in SPD. I chose to create it outside the WebPartZone.

7. Closed and hid the default ListFormWebPart in SPD. Saved changes. Configured the List to use the custom New Form using the ‘Supporting Files’ tab in SPD.

8. Ensured that the ‘Attach File’ link works.

9. Edited the custom New Form in SharePoint using the ‘&ToolPaneView=2’ URL option, and added a Content Editor Web Part (CEWP).

10. Moved the CEWP to the bottom of the page using SPD. The CEWP was also placed outside the WebPartZone.

a. So the order in which the Web Parts are "situated" in the page are:

i. FIRST, Default ListFormWebPart inside the WebPartZone

ii. SECOND, Custom DataFormWebPart outside the WebPartZone

iii. LAST, CEWP outside the WebPartZone

11. Using SharePoint, added JavaScript code, in the CEWP, to hide/show the People Picker control based on the value selected in a drop down list. Check out my post for the JavaScript code.

12. Tested the Form. Custom Fields work, Hide/Show conditions work, and above all ‘Attach File’ works. I also tested it with multiple files and it worked too.

Wednesday, February 3, 2010

Using JavaScript event handlers in SharePoint List Form Page

I created a custom List Form page based on the default NewForm.aspx page. The custom Form includes a drop down list called Security Level, and a People Picker control (which is a pretty handy OOB SharePoint control). The People Picker control needs to be displayed only when a specific value is selected in the Security Level drop down list. Therefore I needed some sort of event handler that would check for the value selected in the drop down list and hide (or show) the People Picker control. And this event handler would need to be triggered on the "load' event of the custom Form, as well as the "onchange" event of the drop down list field.

Credits:
http://blogs.msdn.com/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx

http://boris.gomiunik.net/2008/04/add-functions-and-events-to-sharepoint-form-fields/

Here is the JavaScript solution that I came up with. I left the alert statements in the code, for debugging purposes. Insert this code in a Content Editor Web Part and ensure that it is hidden. Also, place the Content Editor Web Part at the very bottom of the page.

IMPORTANT: Insert the JavaScript OR operator (i.e. double pipe) after the identifier == "" portion in the if() statement in the getTagFromIdentifierAndTitle() function below. For some odd reason the OR operator gets removed whenever I publish the post.


<script type="text/javascript">

//This code runs on the onload event of the custom Form
_spBodyOnLoadFunctionNames.push("getSecurityLevelValue");

function hidePeoplePicker() {
//alert("HIDE");
var control = getTagFromIdentifierAndTitle('textarea','UserField_downlevelTextBox','People Picker');

control.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.style.display="none";

}

function showPeoplePicker() {
//alert("SHOW");
var control = getTagFromIdentifierAndTitle('textarea','UserField_downlevelTextBox','People Picker');

control.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.style.display="";

}

function getTagFromIdentifierAndTitle(tagName, identifier, title)
{

//alert("tagName = " + tagName);
var len = identifier.length;
//alert("Len = " + len);

var tags = document.getElementsByTagName(tagName);
//alert("tags length = " + tags.length);

for (var i=0; i < tags.length; i++)
{

var tempString = tags[i].id;

//alert("tempString = " + tempString);

//NOTE: Insert the OR operator after the identifier == "" portion in the code below
//For some odd reason the OR operator gets removed when I post the blog
if (tags[i].title == title && (identifier == "" tempString.indexOf(identifier) == tempString.length - len))

{

return tags[i];

}

}

return null;

}

function getField(fieldType,fieldTitle) {

var docTags = document.getElementsByTagName(fieldType);

//alert("Length = " + docTags.length);

for (var i=0; i < docTags.length; i++) {

if (docTags[i].title == fieldTitle) {

//alert("Value in getField = " + docTags[i].value);

return docTags[i];

}

}

}

function getSecurityLevelValue() {

//alert("In getSecurityLevelValue");
selectedId = getField('select','Security Level').options[getField('select','Security Level').selectedIndex].value;

//alert("Value in hide =" + selectedId);

if(selectedId != 'Specific User')

{

//alert("NOT Specific User");
hidePeoplePicker();

}

else

{

//alert("Specific User");
showPeoplePicker();

}

}

//This code runs on the onchange event of the drop down list field
getField('select','Security Level').onchange = function() {getSecurityLevelValue()};

</script>

Tuesday, February 2, 2010

Hide People Picker control in SharePoint List Forms

I am working on a project that requires the SharePoint OOB "People Picker" control to be hidden in a List Form Page. In my case, this control was in the "NewForm.aspx" page. But you can use the same code for hiding this control in the "EditForm.aspx" page as well.

I used the following online resources to figure out the JavaScript code to hide the "People Picker" control:

http://blogs.msdn.com/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx

http://www.cleverworkarounds.com/2008/02/07/more-sharepoint-branding-customisation-using-javascript-part-1/

Here is the JavaScript code. Insert this code in the "Source Editor..." window in a Content Editor Web Part.

IMPORTANT: Insert the JavaScript OR operator () after the identifier == "" portion in the
if() statement in the getTagFromIdentifierAndTitle() function below. For some odd reason the OR operator gets removed whenever I publish the post.

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

_spBodyOnLoadFunctionNames.push("hideFields");

function hideFields() {

var control = getTagFromIdentifierAndTitle("Textarea","UserField_downlevelTextBox","People Picker");

control.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.style.display="none";

}

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;

}

</script>

NOTE: The "People Picker" control was embedded 12 levels "deep" from the <tr> tag in my NewForm.aspx, and hence I had to use the code in the hideFields() function with 12 "parent" references. I used the awesome Firebug tool to view this hierarchy and to also find out the elusive tagName, identifier, and title info for the People Picker control. The Firebug tool is a FireFox browser addon, and is incredibly helpful when you need to look at raw HTML and JavaScript code that renders SharePoint pages.