Tuesday, April 03, 2007

WSS/SPS2003 : User Permissions Webpart

UPDATE! As promised here is the solution file : CrossSiteGroupWebPart.rar
And if you just want to install the webpart : CrossSiteGroupWebPartInstall.CAB
And this the list-template you will need : AnalyseNon.stp

I got the question from a customer who wanted to have a view of every user on a site with all the permissions that the user had per list (since you can set permissions per list). Sounds pretty forward huh? :) One challenge I had to face lies in the fact that this customer is a big fan of creating custom sitegroups and cross-site groups.

Another (personal) challenge was that I wanted to publish this information in a custom list on the site where the webpart is dropped upon. You may wonder why I want to publish the information back in Sharepoint again. Well there are 3 reasons : 1. Export to Excel (requirement of the customer) 2. Sorting/Filtertering/Group By of columns 3. Intergration with AD (user presence)

Thus, the first thing was to create a function to retrieve all the permissions per list for each user on a site.

private void GetSecurityForWeb(string url)

{

Stopwatch sp = new Stopwatch();

sp.Start();

ArrayList AnalyzeItems = new ArrayList();

SPSite site = new SPSite(url);

SPWeb web = site.OpenWeb();

try

{

Label1.Text += "<BR>Iterating through "+web.Title.ToString();

SPUserCollection users = web.Users;

foreach (SPUser user in users)

{

foreach (SPList list in web.Lists)

{

System.Collections.Specialized.StringCollection permissions = new System.Collections.Specialized.StringCollection();

if (!list.Permissions.Inherited)

{

SPPermissionCollection perms = list.Permissions;

foreach (SPPermission perm in perms)

{

if (user.ID == perm.Member.ID)

{

foreach (SPRole role in user.Roles)

{

if (role.Type != SPRoleType.None)

{

if (!permissions.Contains(role.Type.ToString()))

{permissions.Add(role.Type.ToString());}

}

}

}

else

{

foreach (SPRole role in user.Roles)

{

if (role.ID == perm.Member.ID)

{

if (role.Type != SPRoleType.None)

{

if (!permissions.Contains(role.Type.ToString()))

{permissions.Add(role.Type.ToString());}

}

else

{

if (!permissions.Contains(role.Name.ToString()))

{permissions.Add(role.Name.ToString());}

}

}

foreach (SPGroup group in role.Groups)

{

if (group.ID == perm.Member.ID)

{

if (!permissions.Contains(perm.PermissionMask.ToString()))

{permissions.Add(perm.PermissionMask.ToString());}

}

}

}

foreach (SPGroup group in user.Groups)

{

if (group.ID == perm.Member.ID)

{

if (!permissions.Contains(perm.PermissionMask.ToString()))

{permissions.Add(perm.PermissionMask.ToString());}

}

}

}

}

}

else

{

foreach (SPRole role in user.Roles)

{

if (role.Type != SPRoleType.None)

{

if (!permissions.Contains(role.Type.ToString()))

{permissions.Add(role.Type.ToString());}

}

else

{

if (!permissions.Contains(role.Name.ToString()))

{permissions.Add(role.Name.ToString());}

}

foreach (SPGroup group in role.Groups)

{

if (!permissions.Contains(group.Name.ToString()))

{permissions.Add(group.Name.ToString());}

}

}

}

//Populating of all the groups where the user is a member of

string groups = string.Empty;

int teller = 1;

foreach (SPGroup group in user.Groups)

{

if (user.Groups.Count == teller)

{groups += group.Name.ToString();}

else

{groups += group.Name.ToString() + " " ;}

teller++;

}

//Adding all the information in an object and pushing this object in an ArrayList

AnalyzeItem item = new AnalyzeItem();

item.Site = web.Title;

item.Username = user.Name;

item.UserID = user.ID.ToString();

item.List = list.Title;

string _perm = string.Empty;

foreach (string perm in permissions)

{

_perm += " " + perm;

}

item.Permissions = _perm;

item.Group = groups;

AnalyzeItems.Add(item);

}

web.Close();

web.Dispose();

}

}

catch(Exception error)

{

Label1.Text += error.Message.ToString();

}

finally

{

site.Close();

site.Dispose();

}

sp.Stop();

Fetch = sp;

AddListItem(url, AnalyzeItems);

}

So what I do is gather all the permissions and store them in a custom class called AnalyzeItem which looks like this :

using System;

using System.Collections;

namespace CrossSiteGroupWebPart

{

/// <summary>

/// Summary description for AnalyzeItem.

/// </summary>

public class AnalyzeItem

{

private string _username = string.Empty;

private string _userid = string.Empty;

private string _site = string.Empty;

private string _list = string.Empty;

private string _group = string.Empty;

private string _permissions = string.Empty;

public AnalyzeItem()

{

//

// TODO: Add constructor logic here

//

}

public string Username

{

get

{

return _username;

}

set

{

_username = value;

}

}

public string UserID

{

get

{

return _userid;

}

set

{

_userid = value;

}

}

public string Site

{

get

{

return _site;

}

set

{

_site = value;

}

}

public string List

{

get

{

return _list;

}

set

{

_list = value;

}

}

public string Group

{

get

{

return _group;

}

set

{

_group = value;

}

}

public string Permissions

{

get

{

return _permissions;

}

set

{

_permissions = value;

}

}

}

}

So now we have all the data stored in the ArrayList, now we want to store this information into a List

private void AddListItem(string url, ArrayList items)

{

Label1.Text += "<BR>Pushing items into list";

Stopwatch sp = new Stopwatch();

sp.Start();

SPSite _Site = new SPSite(url);

SPWeb _Web = _Site.RootWeb;

try

{

Label1.Text += "<BR>Checking if list exists";

SPList analyse = _Web.Lists["Analyse"];

}

catch(Exception error)

{

Label1.Text += "<BR>List not found, therefore creating it";

CreateList(url);

Label1.Text += "<BR>List created";

}

finally

{

_Web.Close();

_Web.Dispose();

_Site.Close();

_Site.Dispose();

}

SPSite site = new SPSite(url);

SPWeb web = site.RootWeb;

SPWeb _compareWeb = site.OpenWeb();

try

{

Label1.Text += "<BR>Emptying list if items already exist";

SPList analyse = web.Lists["Analyse"];

if (analyse.Items.Count > 0)

{

for (int i=analyse.Items.Count-1; i>-1; i--)

{

if (analyse.Items[i]["Site"].ToString() == _compareWeb.Title.ToString())

{

analyse.Items.Delete(i);

}

}

}

Label1.Text += "<BR>List emptied!";

foreach (AnalyzeItem _item in items)

{

SPListItem item = analyse.Items.Add();

item["Title"] = _item.Username;

item["UserName"] = _item.UserID;

item["List"] = _item.List;

item["Permissions"] = _item.Permissions;

item["Groups"] =_item.Group;

item["Site"] = _item.Site;

item.Update();

}

}

catch (Exception error)

{

Label1.Text += "<BR>"+error.Message.ToString();

}

finally

{

web.Close();

web.Dispose();

site.Close();

site.Dispose();

}

sp.Stop();

Import = sp;

}

Now you may wonder what the function CreateList, as you may have guessed by the name it creates a custom list based on a customlist template. See the following code chunk on how I did this. I had some difficulties since the customer has a Portal + teamsites environment so every site beneath the portal is a sitecollection instead of a site. Because of this I could not use the custom list template since this is per site-collection and cannot be referenced over sitecollections. So I choose to physically copy the template from a source site (where the template can ben maintained as well) to the site where the webpart was dropped upon.

<

private void CreateList(string url)

{

//First copy the list template from the source site to the current site

SPSite siteCollection = new SPSite(sourcesite);

SPWeb web = siteCollection.OpenWeb();

SPWeb destweb = SPControl.GetContextWeb(Context);

try

{

SPFolder srcFolder = web.Folders["_catalogs"].SubFolders["lt"];

SPFile srcFile;

if (destweb.WebTemplate == "MPS")

{

srcFile = srcFolder.Files["Analyse.stp"];

}

else

{

srcFile = srcFolder.Files["AnalyseNon.stp"];

}

Label1.Text += "<BR>Template found! " + srcFile.Name.ToString();

try

{

Label1.Text += "<BR>Opening destination web";

SPFolder destFolder = destweb.Folders["_catalogs"].SubFolders["lt"];

SPFileCollection destFiles = destFolder.Files;

Label1.Text += "<BR>Filecollection opened";

string destURL = destFolder.Url + "/" + srcFile.Name;

byte[] binFile = srcFile.OpenBinary();

destFiles.Add(destURL, binFile);

Label1.Text += "<BR>Template saved to "+destURL.ToString();

}

catch(Exception _error)

{

Label1.Text+="<BR>Problem adding template" + _error.Message.ToString();

}

}

catch(Exception error)

{

Label1.Text += "<BR>List creation failed due to : " + error.Message.ToString();

}

finally

{

web.Close();

web.Dispose();

siteCollection.Close();

siteCollection.Dispose();

}

try

{

Label1.Text += "<BR>Trying to create list based on new template";

SPSite destSite = SPControl.GetContextSite(Context);

SPWeb destWeb = destSite.OpenWeb();

Label1.Text += "<BR>Opened the current web";

SPListTemplateCollection customListTemplates = destSite.GetCustomListTemplates(destWeb);

Label1.Text += "<br>#customtemplates" + customListTemplates.Count.ToString();

foreach(SPListTemplate temp in customListTemplates)

{

Label1.Text += "<BR>" + temp.Name.ToString();

}

if (destWeb.WebTemplate == "MPS")

{

SPListTemplate listTemplate = customListTemplates["Analyse"];

destWeb.Lists.Add("Analyse", "", listTemplate);

}

else

{

SPListTemplate listTemplate = customListTemplates["AnalyseNon"];

destWeb.Lists.Add("Analyse", "", listTemplate);

}

}

catch(Exception ___error)

{

Label1.Text += "<BR>" + ___error.Message.ToString();

}

}

As you may have noticed, I use different custom list templates when a different webtemplate is applied to the site. This has to do with site definitions are stored into a custom list template (see KB: Custom List Templates Do Not Appear on the "Create Page" Page of a Site) took me a couple of hours to figure this thing out btw. Since the file is physically there the frustation grew and grew when the object model said there was no custom list template to be found in the gallery :)

And finally we need to build the user interface where the user can select a site and press a button to populate the list. I embedded some javascript to show something an animated gif while the webpart is loading his stuff, so the user doesn't think that the webpart is not functioning. Also I built in a check that only webadmin's can run this tool, since some adminstrative privileges are required when userproperties are queried.

public class CrossSiteGroupWebPart : Microsoft.SharePoint.WebPartPages.WebPart

{

public Stopwatch Fetch;

public Stopwatch Import;

public StringBuilder sb = new StringBuilder();

LinkButton refreshButton;

private Label Label1;

public string nummer = "";

DropDownList drpSiteList;

private const string defaultText = "";

private string text = defaultText;

[Browsable(true),

Category("Miscellaneous"),

DefaultValue(defaultText),

WebPartStorage(Storage.Personal),

FriendlyName("Text"),

Description("Text Property")]

public string Text

{

get

{

return text;

}

set

{

text = value;

}

}

/// <summary>

/// This method gets the custom tool parts for this Web Part by overriding the

/// GetToolParts method of the WebPart base class. You must implement

/// custom tool parts in a separate class that derives from

/// Microsoft.SharePoint.WebPartPages.ToolPart.

/// </summary>

///<returns>An array of references to ToolPart objects.</returns>

// public override ToolPart[] GetToolParts()

// {

// ToolPart[] toolparts = new ToolPart[2];

// WebPartToolPart wptp = new WebPartToolPart();

// CustomPropertyToolPart custom = new CustomPropertyToolPart();

// toolparts[0] = wptp;

// toolparts[1] = custom;

// return toolparts;

// }

/// <summary>

/// Render this Web Part to the output parameter specified.

/// </summary>

/// <param name="output"> The HTML writer to write out to </param>

protected override void CreateChildControls()

{

nummer = this.ID.ToString();

Label1 = new Label();

this.Controls.Add(Label1);

refreshButton = new LinkButton();

refreshButton.Text="<img src='/_layouts/images/REFRESH.GIF' border='0' />Refresh overview";

refreshButton.Attributes.Add("onclick","this.style.display='none';"+

"var obj_msg = document.getElementById('waitmessage"+nummer+"'); "+

"if (obj_msg != null) obj_msg.style.display='';"+

"var obj_tasks = document.getElementById('tasks"+nummer+"'); "+

"if (obj_tasks != null) obj_tasks.style.display='none';" +

"javascript:setTimeout('UpdateImg"+nummer+"()');");

refreshButton.Click+=new EventHandler(refreshButton_click);

this.Controls.Add(refreshButton);

drpSiteList = new DropDownList();

try

{

drpSiteList.DataSource = GetSubWebs();

drpSiteList.DataTextField = "Title";

drpSiteList.DataValueField = "Url";

drpSiteList.DataBind();

}

catch(Exception error)

{

Label1.Text += "<BR>" + error.Message.ToString();

}

this.Controls.Add(drpSiteList);

base.CreateChildControls ();

}

private void refreshButton_click(object o, System.EventArgs e)

{

try

{

GetSecurityForWeb(drpSiteList.SelectedValue.ToString());

UpdateStopWatch(drpSiteList.SelectedValue.ToString());

Label1.Text = "<BR>Refreshing is done";

Label1.Text +="<BR>Fetching items lasted : " +Fetch.Elapsed.Minutes+ "m " + Fetch.Elapsed.Seconds + "s" + " Importing items lasted : " +Import.Elapsed.Minutes+ "m " + Import.Elapsed.Seconds + "s";

Label1.Text +="<BR><a href='Lists/Analyse/AllItems.aspx'>Click here</a> to view the grid";

}

catch(Exception error)

{

Label1.Text += "<BR>" + error.Message.ToString();

}

}

protected override void RenderWebPart(HtmlTextWriter output)

{

SPWeb web = SPControl.GetContextWeb(Context);

if (web.UserIsWebAdmin)

{

try

{

output.Write("<script language=javascript>");

output.Write("function UpdateImg"+nummer+"() {");

output.Write("var img = document.getElementById('taskpic"+nummer+"');");

output.Write("if (img != null) img.src = '_layouts/images/bigrotation2.gif';");

output.Write("return false;");

output.Write("}");

output.Write("</script>");

output.Write("<div id='waitmessage"+nummer+"' style='Z-INDEX:10; DISPLAY:none; WIDTH:100%; POSITION:relative; HEIGHT:100%'>");

output.Write("<table border='0' style='BORDER-COLLAPSE: collapse' width='100%' height='100%' cellspacing='1' bgcolor='#ffffff' bordercolor='#000000'>");

output.Write("<tr>");

output.Write("<td align='middle' bordercolor='#ffffff'>");

output.Write("<img id='taskpic"+nummer+"' src='_layouts/images/bigrotation2.gif'>");

output.Write("</td>");

output.Write(" </tr>");

output.Write(" </table>");

output.Write("</div>");

output.Write("Please select a site to display information from : ");

drpSiteList.RenderControl(output);

refreshButton.RenderControl(output);

Label1.RenderControl(output);

}

catch(Exception error)

{

output.Write(error.Message.ToString());

}

}

else

{

Label1.Text = "You don't have enough permissions to run this webpart";

}

}

To populate the dropdown with webs the copy/paste this following codechunk

private ArrayList GetSubWebs()

{

ArrayList lijst = new ArrayList();

SPWeb web = SPControl.GetContextWeb(Context);

Sites site = new Sites();

site.Title = web.Title.ToString();

site.Url = web.Url.ToString();

lijst.Add(site);

foreach (SPWeb _subweb in web.GetSubwebsForCurrentUser())

{

Sites subsite = new Sites();

subsite.Title = _subweb.Title.ToString();

subsite.Url = _subweb.Url.ToString();

lijst.Add(subsite);

}

return lijst;

}

With this class to store the urls and titles of the webs

using System;

namespace CrossSiteGroupWebPart

{

/// <summary>

/// Summary description for Sites.

/// </summary>

public class Sites

{

private string _url = string.Empty;

private string _title = string.Empty;

public string Url

{

get

{

return _url;

}

set

{

_url = value;

}

}

public string Title

{

get

{

return _title;

}

set

{

_title = value;

}

}

}

}

I will post the solution soonly so you can see for yourself how it all works :)

32 comments:

Anonymous said...

Hi Robin

I'm using SPListItem.update to update the items in a particular list. If the selected field of the list item already has value, there is no problem for my program to update the field to another value.

But if the field has no value initially, my program would not be able to update the field with a value. The system will return the error stated "Object reference not set to an instance of an object.".

I tried to write out the XML schema of the selected list item, and realised that if the field is empty, the schema will not return the field name.

Why is it so and how can i resolve this problem?

Thanks,
Jerry

Robin Meuré said...

Hi Jerry,

can you post your code so I can see what are you doing? :)

Robin

Anonymous said...

Hi Robin

The list record has 3 fields: "Name", "Home No." and "Address". The record only has values for "Name" and "Home No.", and the "Address" field is blank.

Below is my code to update the record when the user enters value for the "Address" field:

SPSite mspSiteCollection = new SPSite(System.Configuration.ConfigurationManager.AppSettings["ContactsList"]);
SPList mspSrcList = mspSiteCollection.OpenWeb().Lists["Contacts"];
SPQuery mspQuery = new SPQuery();

try
{
mspQuery.Query = "<Where><Eq><FieldRef Name='ID'/><Value Type='Integer'>" + gstrRecordID + "</Value></Eq></Where>";

SPListItemCollection mspListItems = mspSrcList.GetItems(mspQuery);

SPListItem mspListItem = mspListItems.GetItemById(Convert.ToInt32(gstrRecordID));

if (mspListItem != null)
{
//Contact Person
mspListItem["ContactName"] = txtContactPerson.Text.Trim();

//Home No.
mspListItem["ContactHomeNo"] = txtHomeNumber.Text.Trim();

//Address
mspListItem["ContactAddress"] = txtContactAdress.Text.Trim();

mspListItem.Update();
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}

I have no problem updating the record with only "Name" and "Home No." fields. But with "Address" field added in the code-behind for record update, I'll get the "Object reference not set to an instance of an object.".

Below is the list schema:

<xml xmlns:s='uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882'
xmlns:dt='uuid:C2F41010-65B3-11d1-A29F-00AA00C14882'
xmlns:rs='urn:schemas-microsoft-com:rowset'
xmlns:z='#RowsetSchema'>
<s:Schema id='RowsetSchema'>
<s:ElementType name='row' content='eltOnly' rs:CommandTimeout='30'>
<s:AttributeType name='ows_ID' rs:name='ID' rs:number='1'>
<s:datatype dt:type='i4' dt:maxLength='4' />
</s:AttributeType>
<s:AttributeType name='ows_ContactName' rs:name='Contact Person' rs:number='2'>
<s:datatype dt:type='string' dt:maxLength='512' />
</s:AttributeType>
<s:AttributeType name='ows_ContactHomeNo' rs:name='Home No.' rs:number='3'>
<s:datatype dt:type='string' dt:maxLength='512' />
</s:AttributeType>
<s:AttributeType name='ows_ContactAddress' rs:name='Contact Address' rs:number='4'>
<s:datatype dt:type='string' dt:maxLength='512' />
</s:AttributeType>
...
...
...
</s:ElementType></s:Schema><rs:data ItemCount="1">
<z:row ows_ID='1' ows_ContactName='Michael Lewis' ows_ContactHomeNo='91234567' ows_Modified='2007-04-07 22:20:54' ows_Created='2007-04-04 15:14:38' ows_Author='1;#User1' ows_Editor='1;#User1' ows_owshiddenversion='1' ows_WorkflowVersion='1' ows__UIVersion='19456' ows__UIVersionString='1.0' ows_Attachments='0' ows__ModerationStatus='0' ows_SelectTitle='1' ows_Order='100.000000000000' ows_GUID='{8295C2F2-22BD-4DC8-9FD1-BA97F39BFF79}' ows_FileRef='1;#Lists/Contacts/1_.000' ows_FileDirRef='1;#Lists/Contacts' ows_Last_x0020_Modified='1;#2007-04-04 15:14:38' ows_Created_x0020_Date='1;#2007-04-04 15:14:38' ows_FSObjType='1;#0' ows_PermMask='0x1b03c4313ff' ows_FileLeafRef='1;#1_.000' ows_UniqueId='1;#{A50BDD8A-342F-4AC0-86F5-2504F28550D4}' ows_ProgId='1;#' ows_ScopeId='1;#{3926090E-27E4-455A-A14B-5DE0A2C3C782}' ows__EditMenuTableStart='1_.000' ows__EditMenuTableEnd='1' ows_LinkFilenameNoMenu='1_.000' ows_LinkFilename='1_.000' ows_ServerUrl='/Lists/Reports/1_.000' ows_EncodedAbsUrl='http://mycontact.com/Lists/Contacts/1_.000' ows_BaseName='1_' ows_MetaInfo='1;#' ows__Level='1' ows__IsCurrentVersion='1' />
</rs:data>

Hope you could guide me to resolve the issue.

Note: I have to replace the "<" and ">" with "<" and ">" coz' I couldn't post my code with HTML tags.

Thanks,
Jerry

Robin Meuré said...

Hi Jerry,

well maybe the problem is that the field name is incorrect. When you open the editform.aspx (or newforms.aspx) page of the list. Go check out what the fieldname is in the source of the page. There is something like this :

FieldName="Address"
FieldInternalName="WorkAddress"
FieldType="SPFieldNote"


When you use the item["fieldname"] thing, you can only use the internal fieldname.

And btw why are you using the SPQuery when you also use the GetItemByID method?

I think your code is cleaner by this way :

SPSite mspSiteCollection = new SPSite(System.Configuration.ConfigurationManager.AppSettings["ContactsList"]);
SPList mspSrcList = mspSiteCollection.OpenWeb().Lists["Contacts"];


try
{

SPListItem mspListItem = mspSrcList.Items.GetItemById(Convert.ToInt32(gstrRecordID));

if (mspListItem != null)
{
//Contact Person
mspListItem["ContactName"] = txtContactPerson.Text.Trim();

//Home No.
mspListItem["ContactHomeNo"] = txtHomeNumber.Text.Trim();

//Address
mspListItem["ContactAddress"] = txtContactAdress.Text.Trim();

mspListItem.Update();
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}

Anonymous said...

Hi Robin

Thanks for the great help!

Cheers,
Jerry

Robin Meuré said...

Hi Jerry,

no problem! I'm glad I could help you :)

Anonymous said...

I have such a requirement to list all the users and their permissions. We need this to show auditors, who has access to sensitive information. So looking forward to your demo. Will you be making the code available as a download web part?

Anonymous said...

Thanks for making the code available ready for testing.

Robin Meuré said...

No problem, if you've got any questions don't hesitate to do so!

Henry Echardt said...

Thank you for publishing this sophisticated code! The task to retrieve user permissions is not as simple as one might think. At the same time as it comes right after you create the first site collection and build the first item list the task to set access rights and redistribute permissions is of the most frequently used tasks. But the standard control is really lacking the usability. As an admin I must say that I sometimes get completely stuck when I need to observe who and where has which type of access. Additional problems that I basically experience is the need to control a set of rights because as we know sometimes having the Full access permission is not enough to gain the access to the list and see all the available options. Being an admin I am not so experienced in coding the functionality myself and was wondering why it is not implemented by default. Recently I new the there are some third-party solutions that indeed allow maintaing lists security settings from within the basic tool interface as I prefer to use. Thanks to the latest Teched show, I found there a lot of information on the sharepoint management topic and specifically the sharepoint security management tool showcased by Scriptlogic. Maybe it's just me although my friend likes it too but I basically prefer to control the site from the server and see the server security at the same time.

Robin Meuré said...

Hi Henry,

that's exactly the reason why I build this! As I look at the screenshot from the page of the tool you mentioned I still see only groups and security are displayed. Where as my tool displays in which groups the user resides and thus what all his rights are on a particular list.

Furthermore, I find the 'new' UI in MOSS/WSSv3 for administering users less userfriendly than the 2003 version.

Scott Gerber said...

This is fantastic - exactly what I need to solve my problem...but when I import the webpart to MOSS 2007 I cannot get it to work. Am I doing something wrong? Should I be installing it in a different way? Any help would be greatly appreciated.

Scott

Thanks for making this available to use newbies!

Robin Meuré said...

Hi Scott,

i've build this webpart using the ObjectModel of 2003. I'm guessing that some things I do in the code does not work anymore in 2007.

Do you get specific errors? If so, please post them.

If I got time I'll try to rebuilt the webpart to use in MOSS.

Scott Gerber said...

Hi Robin - Thanks for the quick reply! Okay we found out how to install the webpart using STSADM on the server but the web part does not appear in the WebPart Gallery. I then tried to upload the template to our MOSS Server and it does not appear either. It has to be said we are new at this...but have followed the STSADM syntax to the T. I appreciate your help - and time.

Scott

Emanuele said...

Hi Robin, I was trying to retrieve user permission level for the user currently connected in the MOSS 2007 environment.
I'm trying to retrieve user permission level directly into a Infopath2007 form...is there a way to do that?( till now I retrieved user profile data and showed in the form fields).

I am a newbie of MOSS2007 and Infopath2007,

Thanks in advance for your time!

Emanuele

Emanuele said...

Hi Robin,
I'm trying to retrieve the user permission level (of the user connected to my MOSS2007 environment) from an Infopath2007 form...(Till now I retrieved user profile data (UserName, Account, etc.)and showed in the form fields).

Is there a way to do that without using the webpart you posted?

Thanks in advance for your time!
Emanuele

Robin Meuré said...

Hi Emanuele,

yes i think it is possible, you will have to write your own webservice which will receive the username from InfoPath and within the webservice you do a call against SharePoint to retrieve it and pass the result back to InfoPath.

What kind of permissionlevel are you seeking? Site/web/list/item ?

Emanuele said...

Hi there!thanks for your answer,here you are my progresses

1) I have found a list of web services here:
http://itfootprint.wordpress.com/2007/06/24/built-in-sharepoint-web-services-for-sharepoint/

2) I took the one for the permissions: "/_vti_bin/Permissions.asmx"

I've included the web reference in my c# code behind the Inforpath form, FINALLY I have 2 web references:
First:vti_bin/UserProfileService.asmx
Second: _vti_bin/Permissions.asmx (named "PermissionService" in the code)

Actually I'm looking for the permission at item/list level

this is the code:

PermissionService.Permissions permissionService = new PermissionService.Permissions();


permissionService.Credentials = System.Net.CredentialCache.DefaultCredentials;

XmlNode permissionNode = permissionService.GetPermissionCollection("List_Name", "List");

Emanuele said...

Ah, I forgot to say, every time I get an exception:

"Microsoft.SharePoint.SoapServer.SoapServerException"

so I can't fill in the xml with the permissions, the following is the page where I've found the code to use:

http://msdn2.microsoft.com/en-us/library/permissions.permissions.getpermissioncollection.aspx

I did exactly the same, I am pretty unexperienced and I can't manage that kind of exception.

thank you very much for your time!

Emanuele

Robin Meuré said...

Try creating a custom webservice alone instead of calling webservices in InfoPath code. And call that webservice in InfoPath as an external connection.

Emanuele said...

Hi Robin!
I finally got it, my XmlNode contains all the details regarding the permissions of the site...I've made it with the sharepoint web service passing the username and pwd of the Administrator, who has unique access to those informations

The problem is that I want to retrieve the permissions of the single user who's editing the Infopath form taken from the same site (or at least the GroupName of the user to link it to a permission mask)...

any idea to suggest?

thanks again,

Manu

Robin Meuré said...

Oi,

mind if you copy/paste your code here (or mail it) to see what you got already and how to implement the permissionlevel fetch? :)

Emanuele said...

Hi Robin,
thanks for your post, I finally found a webapage with a VB function which does more or less the same, I translated it (at my best) working directly in the server which hosts MOSS2007 (since I needed the Microsoft.Sharepoint library).
This is the page where I've foud the code:

http://www.vbdotnetheaven.com/UploadFile/ssahmed/spuserperm09192006044916AM/spuserperm.aspx

I translated the VB code to C#, this is the method:

private string CheckGroupRights(string FolderPath, string SubSite, string UserLogin)
{
string status;

try
{
SPSite siteCollection = new SPSite(FolderPath);

SPWeb site = siteCollection.OpenWeb(SubSite);

SPUserCollection allUsers = site.Users;

SPUser user;

foreach (User foundUser in allUsers)
{
if (user.LoginName.ToUpper() == UserLogin.ToUpper())
{
SPRoleCollection allGroups = user.Roles;

SPRole group;

foreach (SPRole foundGroup in allGroups)
{
int right;

right = (int)(foundGroup.PermissionMask && SPRights.ViewListItems);

if (right == SPRights.ViewListItems)
{
string strStatus = "User " + UserLogin + " has Reader permissions in " + FolderPath + "/" + SubSite + ".";

status = strStatus;

return strStatus;

}
}
}

}
}

catch
{
}



return status;
}

Still I have problems, I got warnings about the obsolescence of SPRoleCollection,SPUserCollection and others, but they are only warnings.

When I run it after 1 min I get a sort of execution time out, I think something's is wrong in the line:
right = (int)(foundGroup.PermissionMask && SPRights.ViewListItems);

I try to get a logic AND from the permission mask of the Group and the defined rights,

any idea's welcome,

thanks again,

Manu

Robin Meuré said...

Hi,

try using this code (which I haven't tested but it does compile ;)) in your custom webservice :

private bool Checkuser(string url, string listname, string username)
{
SPSite site = new SPSite(url);
SPWeb web = site.OpenWeb(url);
SPList list = web.Lists[listname];

bool status = false;


foreach (SPUser user in web.Users)
{
if (username == user.LoginName)
{
foreach (SPRoleAssignment assignment in list.RoleAssignments)
{
if (assignment.Member.ID == user.ID)
{
foreach (SPRoleDefinition def in assignment.RoleDefinitionBindings)
{
if (def.BasePermissions == SPBasePermissions.ViewListItems)
{
status = true;

}
}
}

foreach (SPGroup group in groups)
{
if (assignment.Member.ID == group.ID)
{
foreach (SPUser groupuser in group.Users)
{
if (groupuser.ID == user.ID)
{
if (def.BasePermissions == SPBasePermissions.ViewListItems)
{
status = true;

}
}
}
}
}

}
}
}

web.Close();
web.Dispose();

site.Close();
site.Dispose();

return status;
}

salwa said...

I found your webpart a great one. But after i install it in my WSS 3.0 server i counter the following error when i try to use the webpart:
Iterating through Eng
Pushing items into list
Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
Iterating through Eng
Pushing items into list
Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
Iterating through Eng
Pushing items into list
Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.

I need also user guide or more detail about it's feature please.

Jill said...

Robin - I would be very interested in using the web part for our MOSS 2007 environment. We have a client portal that we are building that this would come in very handy. Has anyone successfully implemented your WSS 3.0 version in MOSS 2007 without needing code changes? You mentioned in your post that you might be working on a version for MOSS 2007. Do you have a release date determined? Thanks!!

Anonymous said...

Will you be updating this for MOSS 2007?

Robin Meuré said...

Hi guys,

i would recommended you check out the following tool which does the same thing as mine does but this ons is supported for 2007 ;)

http://blogs.msdn.com/mcsnoiwb/archive/2008/09/25/sharepoint-access-checker-web-part-v1-3-0.aspx

buy wow gold said...

When the Wow Gold wolf finally found the wow gold cheap hole in the chimney he crawled cheap wow gold down and KERSPLASH right into that kettle of water and that was cheapest wow gold the end of his troubles with the big bad wolf.
game4power.
The next day the Buy Wow Goldlittle pig invited hisbuy gold wow mother over . She said "You see it is just as mttgamingI told you. The way to get along in the world is to do world of warcraft gold things as well as you can." Fortunately for that little pig, he buy cheap wow gold learned that lesson. And he just agamegold lived happily ever after!.

Anonymous said...

Hi Robin,

I installed this webpart on wss 3.0 but when i refresh the button it gives me this error

Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
Iterating through Eng
Pushing items into list
Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
Iterating through Eng
Pushing items into list
Checking if list exists
List not found, therefore creating it
The Web application at http://portal/sites/teamsitethathoststemplate could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.

can you tell me what i am doing wrong...i am new to sharepoint so please help me out on this.
thanks,
steven

Anonymous said...

Steven and Salwa:

Did you ever resolve the "http://portal/sites/teamsitethathoststemplate" problem to actually make this work?

Robin Meuré said...

Hi Steven and Salwa,

I'm not updating this stuff anymore. I recommend you use the other tool I mentioned a couple of comments back that's on CodePlex.