Posts mit dem Label Sharepoint werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Sharepoint werden angezeigt. Alle Posts anzeigen

Mittwoch, 17. April 2013

Sharepoint Item Level Permissions via List Settings in C#

A forum post made me aware of the possibility to set item level permissions for a sharepoint list in a configurative way, without the need of writing an event receiver. Just jump to your list and navigate to

[Ribbon Region] List Tools -> [Tab] List -> [Group] Settings -> [Button] List Settings

On the list settings page select

[Region] General Settings -> [Link] Advanced settings -> [Region] Item-Level Permissions

You should see something like this:


This is great because it enables me to do a lot of the stuff I have done with event revievers before, so it saves me a lot of code.

But of course I want to set these in code, for being able to deploy my development by menas of an wsp-file. Say I want to configure the list in a way that a user can only see and edit the items he created. I was browsing thorugh the properties of the SPList-object and found something that seems a little bit like a hack to me, but here is the way it goes:

SPList myList = GetMyList();
myList.ReadSecurity = 2;
myList.WriteSecurity = 2;
myList.Update();


Yeah, belive it or not, those two are integer fields. According to MSDN we can set the following values for ReadSecurity:
  • 1 - All users have Read access to all items. 
  • 2 - Users have Read access only to items that they create. 
For WriteSecurity the following values are allowed:
  • 1 — All users can modify all items.
  • 2 — Users can modify only items that they create.
  • 4 — Users cannot modify any list item.
The programming model for this is really ugly, but it serves the need. This applies to Sharepoint 2010 where I tested it, and according to MSDN it is the same for shapreoint 2013.

Enjoy!


Mittwoch, 28. November 2012

Sharepiont item level rights and a fluent Interface

Fluent Interfaces are a common thing nowdays, and evereyone who ever used Linq knows about them. Other products use them as well. But have you ever tried to write on on your own? Lately I did, and I found that there are different ways to do it depending on the situation where you are starting from.

My sceanrio was, that I wanted to implement a solution for running to set item permissions on a sharepoint list item. You need elevated privileges to do that if you are not an admin. Usually, in the ItemAdded event reciever you do it like so:

var item = properties.ListItem;
var web = properties.web;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
   using (SPSite oSite = new SPSite(web.Site.Url))
   {
     using (SPWeb oWeb = oSite.OpenWeb())
     {
       SPList oList = oWeb.Lists.GetList(item.ParentList.ID, false);
       SPListItem oItem = oList.Items.GetItemById(item.ID);

       oItem.BreakInheritedRights();
      
       SetRights(oWeb, oItem);
       
       oItem.Update();
     }
   }
});

You get the item and the web from the event properties. But in the delegate you must get a new instance of the web, the list and the item because the outside references are running in the low privileges context. The Method BreakInheritedRights is an extender that calls BreakRoleInhreitance on the item and removes all current RoleAssignments. The not shown method SetRights sets the actual rights to the item. I needed to do this for several lists and the above code was to obscure and hard to understand. So I decided to implement it something like that:

var item = properties.ListItem;
var web = properties.web;

SecurityHelper.RunWithElevatedPrivileges()
        .OnSite(web.Site.Url)
        .OnListItem(item.ParentList.ID, item.ID)
        .Execute(setItemPermissions);

This seemed to be more readable to me. So I was in  the lucky situation that this functionality was enterly new. So I have choosen the easiest way to do it: by creating a set of classes to build up your langauage. So I came up with the following set of classes:

public class SecurityHelper
{
  public static SecurityHelper RunWithElevatedPrivileges() { ... }
  public RunWithElevatedPrivilegesSiteContext OnSite(string url) { ... }
}


public class RunWithElevatedPrivilegesSiteContext
{
  public void Execute(Action<SPWeb> actionToRunElevated) { ... }
  public RunWithElevatedPrivilegesListItemContext OnListItem(Guid listId, int itemId) { ... }
}

public class RunWithElevatedPrivilegesListItemContext
{
  public void Execute(Action<SPWeb, SPListItem> executeOnListItem) { ... }
}

The static RunWithElevatedPrivileges method is the entry point. It allows us by calling the OnSite-Method to create a site context to execute elevated code, modeled throug the class RunWithElevatedPrivilegesSiteContext which gets passed in the site url. Using its Execute-Method we can run elevated code that only needs the web. If you want a list item to be in context, you have to call the OnListItem-Method to get a RunWithElevatedPrivilegesListItemContext instance. This allows you to pass in a callback expecting web and list item. This will be obtained by the Execute-Method in the following way:

public void Execute(Action<SPWeb, SPListItem> executeOnListItem)
{
  SPSecurity.RunWithElevatedPrivileges(delegate()
  {
    using (SPSite site = new SPSite(_siteUrl))
    {
      using (SPWeb web = site.OpenWeb())
      {
        SPList list = web.Lists.GetList(_listId, false);
        SPListItem item = list.Items.GetItemById(_itemId);

        executeOnListItem(web, item);
      }
    }
  });
}

If things get more complex, you shoud prefer to define interfaces that define your language an implement them on your classes or you can use extensions methods like in LINQ.

Have a fluid coding!