Home > MOSS 2007 > Item Level Permission in workflow CreateTaskXXX activities

Item Level Permission in workflow CreateTaskXXX activities

September 27th, 2007 Leave a comment Go to comments

Both CreateTask and CreateTaskWithContentType  activities  have a property called ” SpecialPermissions ” that takes a hashtable of key-value pairs of type string and SPRoleType. Setting the SpecialPermissions property  in your code will strip out all existing permissions inherited from the parent list(Workflow Task List) and only adds permissions for each pair you added to the hashtable .

   private void createTask(object sender, EventArgs e)
{
…….
CreateTask task1 = sender as CreateTask;
HybridDictionary permsCollection = new HybridDictionary();
permsCollection.Add(taskProps.AssignedTo, SPRoleType.Administrator);
task1.SpecialPermissions = permsCollection;
}

Alternatively, If you are using “CreateTaskWithContentType” activity, you have one other option : The event handler bound to your content type. Here is how I’d do it:

1) I create the Task using “CreateTaskWithContentType” activity from my workflow. Obviously, I already have a content type in place.

2) I have also attached an event handler to the content type I use above. Oops! I forgot to say that there is no way you can visually do that (except this one), so I use a programmatic approach to assign an event handler to my content type when the feature that contains my content type get activated.

3) So I have to create a Feature that contains the content type (MyTaskContentType.xml is content type definition which I will skip for the sake of code brevity)

<?xml version=”1.0″ encoding=”utf-8″ ?>
<Feature Id=”5FED1202-C6B8-453e-9EC0-F328655ED4DC”
Title=”My Workflow Task Content Types”
Description=”….”
Version=”12.0.0.0″
Scope=”Site”
xmlns=”http://schemas.microsoft.com/sharepoint/
ReceiverAssembly=”DevHorizon.SharePoint.Workflows, Version=1.0.0.0, Culture=neutral, PublicKeyToken=207a12b7817b805c”
ReceiverClass=” “DevHorizon.SharePoint.Workflows.AddConentTypesEventHanlders”>
<ElementManifests>
<ElementManifest Location=”DivRepTask.xml” />
<ElementManifest Location=”HRAdminTask.xml” />
</ElementManifests>
</Feature>

4) I create a feature receiver class for this feature, I get a reference to the content type and attach the event handler to it programmatically:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
using (SPSite siteCollection = (SPSite) properties.Feature.Parent)
{
using (SPWeb web = siteCollection.OpenWeb())
{
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); SPContentType ctMyTask = web.ContentTypes[“My Conent Type”];
ctMyTask.EventReceivers.Add(SPEventReceiverType.ItemAdded, a.FullName,”MyTaskItemEventReceiver”);
ctMyTask.Update();
web.Update();

}
}
}

5) Now,I need to create an event handler class named “MyTaskItemEventReceiver” that inherits from SPItemEventReceiver.Make sure you decorate this class with the right attributes to target to the featureId that contains your content type and the content type Id that you are writing this event handler for. You also need a unique GUID for your event handler

[TargetContentType(“feature id goes here”, “content type id goes here”)]
[Guid(“and here is the unique id for your enevnt handler”)]

6) In ItemAdded method of your event handler add the following code:

DisableEventFiring();
SPListItem listItem = properties.ListItem;
try
{
listItem.BreakRoleInheritance(false);
listItem.Update();
listItem =SetItemLevelPermissions(listItem.Web, listItem, SPRoleType.Contributor, listItem[“Assigned To”].ToString());
listItem.Update();
}
catch (Exception ex)
{
//Add error handling code here
}
EnableEventFiring();

7) And finally add this helper method somewhere accessible from within your event handler

public static SPListItem SetItemLevelPermissions(SPWeb setSPWeb, SPListItem setListItem, SPRoleType setRoleType, string assignedTo)
{
int index = assignedTo.IndexOf(‘;’);
int id = Int32.Parse(assignedTo.Substring(0, index));
SPUser user = setSPWeb.SiteUsers.GetByID(id);
SPRoleDefinition roleDefinition = setSPWeb.RoleDefinitions.GetByType(setRoleType);
SPRoleAssignment roleAssignment = new SPRoleAssignment(user.LoginName, string.Empty, string.Empty, string.Empty);
roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
setListItem.RoleAssignments.Add(roleAssignment);
return setListItem;
}

Now when your workflow creates a task, its item level permission will be broken and set to “assigned to” field.Happy ending!

Categories: MOSS 2007 Tags:
  1. November 28th, 2007 at 09:04 | #1

    Hi,

    I’ve got the same results with no content type or handler. I simply used the OnTaskCreated event-task of sharepoint with the following code:

    private void OnTaskCreated_MyTask_Invoked(object sender, ExternalDataEventArgs e)
    {
    WorkflowHelper.SetTaskItemContributor(this.aoAtivar.WorkflowProperties.TaskList, (e as SPTaskServiceEventArgs).afterProperties);
    }

    … where WorkflowHelper is a class of mine with the method:

    static public void SetTaskItemContributor(SPList taskList, SPWorkflowTaskProperties taskProps)
    {
    SPListItem listItem = taskList.Items.GetItemById(taskProps.TaskItemId);
    SPRoleDefinition roleDefinition = listItem.Web.RoleDefinitions.GetByType(SPRoleType.Contributor);

    SPUser user = listItem.Web.Users[taskProps.AssignedTo];

    //Adds the assigned user as the only contributor of the item
    SPRoleAssignment roleAssignment = new SPRoleAssignment(user.LoginName, user.Email, user.Name, user.Notes);
    roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
    //If we don’t break, it doesn’t work!
    listItem.BreakRoleInheritance(false);

    listItem.RoleAssignments.Add(roleAssignment);

    //Updates de OM of MOSS (always needed
    listItem.Update();
    }

    Igor

  2. Reza Alirezaei
    November 28th, 2007 at 11:52 | #2

    Yes, you are absolutely right. I knew you can write the same code at taskCreated activity level and have the same result. By easier way of doing this, I meant something at the Task activity properties or event handler level and not writing custom code for it or writing less custom code. The main reason I decided to decouple this from workflow itself was to have the same kind of behavior when someone adds the task directly to the task list outside the context of Workflow. I personally think this way is much cleaner than hard coding the functionality @ workflow level , but obviously it means more work for dev and deployment. You also can attach this functionality to other lists /doc libs and kill multiple birds with one stone:)

  3. Martin
    December 4th, 2007 at 10:32 | #3

    Hello Reza,

    I’m trying to set the RoleAssignments of the workflowProperties.Item and wonder if you can shed any light on it.

    I have read that because Workflow caches the Item it’s working on, one should not use the normal SPListItem.Update api. Instead use IListItemService.UpdateListItem

    I’ve tried sticking in a CallExternalMethodActivity that references IListItemService.UpdateListItem, but currently I get “Exception has been thrown by the target of an invocation”, and then “Error updating a list item”.

    I’ve given the activtiy it’s own token, set the ID to a new Guid (in MethodInvoking). itemId, itemProperties and listId are set to Activity=myWorkflow, Path-workflowProperties.ItemId, Item.Properties and ListId respectively.

    Any ideas?

    Thanks
    Martin

  4. Reza Alirezaei
    December 5th, 2007 at 01:14 | #4

    Hello Martin,

    If you running this workflow against a document library with “Require documents to be checked out before they can be edited?” option set to “YES”, you must perform CheckOut,update
    and then Check back in. Apart from caching issues , when you try SPListItem.Update or SPListItem.SystemUpdate , will you get the same error?

  5. Martin
    December 5th, 2007 at 03:46 | #5

    Hi Reza,

    Thanks for the reply. I have found that changing the RoleAssignments is “special” in that once I get it right, the change is immediate – no need for a call to update. Getting it right, includes realising the changed RoleAssignment needs to be re-added to the RoleAssignments collection. Ie having got my specific role assignment by iterating through the collection, it is not a connected/live version.

    Martin

  6. Lee
    October 9th, 2008 at 02:48 | #6

    Hi,

    I’m trying to set RoleAssignment to the splistitem throw an error
    “This operation is not allowed on an object that inherits permissions.”
    any one help me out of this error. Here is the Code

    SPSite site = new SPSite(“http://servername/”);
    SPWeb web = site.AllWebs[“sitename”];
    SPListItemCollection listItems = web.Lists[“Announcements”].Items;
    web.AllowUnsafeUpdates = true;
    SPListItem itm = listItems.Add();

    //itm.BreakRoleInheritance(true);
    itm[“Title”] = “Test 09-10-2008”;
    itm[“Body”] = “sdfsdfsdf sdfs sdf Sampfle sdfsdsdfsdfsdf”;

    SPRoleDefinition roledef = web.RoleDefinitions.GetByType(SPRoleType.Reader);
    SPRoleAssignment roleassign =
    new SPRoleAssignment(“user name”, string.Empty, string.Empty, string.Empty);

    if (!roleassign.RoleDefinitionBindings.Contains(roledef))
    roleassign.RoleDefinitionBindings.Add(roledef);

    if (!web.HasUniqueRoleAssignments)
    itm.BreakRoleInheritance(false);

    itm.RoleAssignments.Add(roleassign); // Error Occur

    itm.Update();
    web.AllowUnsafeUpdates = false;

    Regards
    Lee

  7. Reza Alirezaei
    October 9th, 2008 at 09:19 | #7

    u sure itm.BreakRoleInheritance(false); is getting executed? looks like inheritance is not broken!

  8. Asmand
    November 18th, 2008 at 05:21 | #8

    A somewhat related question. I want to set the permissions for a task to “Read” at the end of the workflow. Can this be accomplished in any other way than with an event handler on the task list that looks for completed tasks? I naively tried a code activity at the end of the workflow, but since the workflow was still running, I was not able to change permissions on the tasks. I can probably do an “Update task” activity and in that one somehow set permissions? What would be the nicest solution?

  9. Saumil
    November 28th, 2008 at 09:22 | #9

    Hi Friend,
    I want to give permission on list item dynamically
    when user is added from Ad, on site it has only read and on a list only
    add/EDit

    Help..

  10. PrashanthSpark
    December 14th, 2009 at 00:31 | #10

    I want to ReAssign The same Task Item to Sharepoint Group programitacally.

    I tried lot of options in onTaskChanged1_Invoked()
    workflowProperties.TaskList.Fields[“Assigned To”] = “”;

    Hashtable hTable = new Hashtable();
    hTable.Add(SPBuiltInFieldId.AssignedTo, @”Q Team”);
    hTable.Add(SPBuiltInFieldId.Title, “Assigned to Q Team”);
    SPListItem _item = workflowProperties.TaskList.GetItemById(onTaskChanged1_AfterProperties1.TaskItemId);

    bool outcome = SPWorkflowTask.AlterTask(_item, hTable, false);

    anyway breaking inheritance can i achieve my requirement.

    Please guide me

    Regards
    PrashanthSpark

  11. September 4th, 2010 at 17:06 | #11

    I followed your method of writing an event handler for the itemAdded event on the list item and restricted the permission to Assigned person only, this part works great but now my Collect Feedback activity in SPD workflow does not return the status or comment fields in the workflow variables. If i disable the event handler, i’m able to read the feedback columns just fine, it sounds like a permission issue, any workaround for this?