Wednesday, November 16, 2011

Event handler to archive items when deleted

A person just asked this on a mailing list I am on, so I thought I'd share this code. The requirement - copy a list item that is deleted to an archive list. The solution - event receiver that copies the item. The code below does the job, but again is only a sample - you still need to implement error handling, and there are hard coded variables there you will want to change.
Note: this code is specifically for list items, not for documents in document libraries. You can easily change the code to support documents as well (see the CopyAttachments function for an example on how to copy files).

public override void ItemDeleting(SPItemEventProperties properties)
       {
           //note: may require permission elevation.
           //TODO: add error handling

           //get the item being deleted
           SPListItem item = properties.ListItem;
           //get the target list
           SPList targetList = properties.Web.Lists["Announcements Archive"];
           //create the new item
           SPListItem newItem = targetList.Items.Add();
           //copy the list item to the target
           foreach (SPField f in item.Fields)
           {
                if (!f.ReadOnlyField && newItem.Fields.ContainsField(f.InternalName))
                    newItem[newItem.Fields.GetFieldByInternalName(f.InternalName).Id] = item[f.Id];   
           }
           //copy "special" read only fields that can be written to
           newItem["Created By"] = item["Created By"];
           newItem["Modified By"] = item["Modified By"];
           newItem["Modified"] = item["Modified"];
           newItem["Created"] = item["Created"];
           newItem.SystemUpdate(false);
           CopyAttachments(item, newItem);
           base.ItemDeleting(properties);
       }

Note - for the "CopyAttachments" I used code that I published in the past: http://www.sharepoint-tips.com/2008/11/how-to-copy-attachments-from-one-list.html

Tuesday, November 15, 2011

Setting item permissions for new items

A common question that I recently answered in a sharepoint conference is how to make a sharepoint list only show items to the users who wrote the items, and users specified in the item's properties.
A good example of this is a task list where only the original creator of the task and the assignee can see and change the task. This is impossible to do in sharepoint out of the box, and that is where we, as developers, come in.
The way to do it is by developing a simple event handler and attaching it to the list. I prefer to attach to ItemAdded and ItemUpdated - put the exact same code in both events (so that people can reassign the task). The code sample below is a good starting point for you to figure out how to do this. The code sample assumes you know how to use visual studio to create a new event handler, and is meant only as a sample - it doesn't have error handling and it does have some hard coded values for a task list that you may want to change.

public override void ItemAdded(SPItemEventProperties properties)
        {
            //get the list item that was created
            SPListItem item = properties.ListItem;
            //get the author user who created the task
            SPFieldUserValue valAuthor = new SPFieldUserValue(properties.Web, item["Created By"].ToString());
            //get the "assigned to" user. Note - this will throw an error if the task is not assigned to anyone - implement error handling!
            SPFieldUserValue valAssignedTo = new SPFieldUserValue(properties.Web, item["Assigned To"].ToString());
            //disconnect the security from the list, and delete all permissions
            item.BreakRoleInheritance(false);
            //create the object that will hold the roles for the author user
            SPRoleAssignment authorRole = new SPRoleAssignment(valAuthor.User);
            //create the object that will hold the roles for the assigned to user
            SPRoleAssignment assignedToRoles = new SPRoleAssignment(valAssignedTo.User);

            //get the contribute role from the web. Alternatively use code to create a new role definition with custom permissions.
            SPWeb oWebsite = properties.Web;
            SPRoleDefinitionCollection collRoles = oWebsite.RoleDefinitions;
            SPRoleDefinition oRoleDefinition = collRoles["Contribute"];

            //assign permissions to task author
            authorRole.RoleDefinitionBindings.Add(oRoleDefinition);
            item.RoleAssignments.Add(authorRole);
            //assign permissions to task assignee
            assignedToRoles.RoleDefinitionBindings.Add(oRoleDefinition);
            item.RoleAssignments.Add(assignedToRoles);
            //update the item
            item.Update();
            base.ItemAdded(properties);
        }

You can download the entire code sample as a visual studio project from my company's site's code samples document library at http://www.extelligentdesign.com/Code%20Sample%20Downloads/Forms/AllItems.aspx. You will want to change the project's properties to point to your local development site before debugging.