Friday, November 27, 2009

How to: Out of box Approval Workflow issue and solution - Part 2

Hi all,

If you have noticed that SharePoint Approval workflow, you will get an issue. Please refer to my part 1 blog.

PROBLEM:
Apparently, when an item is attached to Approval workflow to control content approval for a user with contribute permissions, they can approve their own major version of an item through the approve button in the workflow.

There a no way to configure the workflow so the site members (contribute permission level) can not approve their own major versions of an item. Its really a MAJOR drawback of out of the box Approval Workflow. 

For e.g.  
Suppose we have a document library called as "Business Services". We attach an OOTB SharePoint "Approval" workflow to it. Permissions to this document library has 2 users:
i) vm\local1 (with contribute permissions)
ii) vm\approver (with approver permissions).

Testing for vm\local1: 


>> vm1\local1 logs in.
>> Goes in to "Business Services"
>> Uploads a document.
>> Check in the document, right click and choose "Publish a major version"
>>  Approval workflow kicks in. local1 enter the approver name and hit the "Start" button.
>> This document will be in "Pending" status and workflow status will be "In Progress".
>> a) Right click on the document, choose the "Approve/Reject" from the ECB. We will receive Error Access Denied. EXPECTED BEHAVIOR
     b)  Click on the "In Progress" link, Go to the task list, try to approve this document. Approval workflow will be completed and version 1.0 approval status "Approved". NOT EXPECTED BEHAVIOR


Workaround: 


In my previous blog, I had NOT touched the OOTB Approval workflow, but I changed TASK list's behavior. But in that blog, actually checking the permission for the TASK and not for the "Business Services". In this blog, I corrected the behavior. This time, I have verified permission for "vm\local1" on the "Business Services". 

My Task's event handler: 


public override void ItemUpdating(
SPItemEventProperties properties)
       {
           base.ItemUpdating(properties);

           this.DisableEventFiring();

           using (SPWeb currentTeamSite = properties.OpenWeb())
           {
               // Delcare variables/Objects
               bool isApprover = false;                            //Flag to check permission
               string currentUser = string.Empty;              //Get current user (For e.g. vm\local1)

               // Get the current item
               SPListItem currentItem = properties.ListItem;

               /* STEP1:
                   We need to get the current logged in the user. In our case, its vm\local1. Bear in mind that, we have hooked the "TASK" list as the event handler. through event properties we can extract the current logged in the user
               */

               // Get the value display name of the current logged in user and Created by Field of the current item
               currentUser = currentItem["Author"].ToString(); // For e.g. 21;#vm\local1
               SPUser user = currentTeamSite.AllUsers.GetByID(properties.CurrentUserId); // extract the ID. such as 21

               /* STEP2
                   THIS PART THE MOST IMPORTANT PART OF THE CODE. We get the currentUser. But we need to parent list which is "Business Services" and get the permission for the user on that document library. In the task list, we always have reference to the workflow.  Therefore, currentItem has workflowListId and through which we can get the parent list.
               */
                  // Get the Parent list (such as Business Services, Development etc. currentItem is from Task lists)
               SPList parentList = currentItem.ParentList.ParentWeb.Lists[new Guid(currentItem[SPBuiltInFieldId.WorkflowListId].ToString())];
          
               /* STEP3: 
                  Now, we have to get permission of current logged in user on the "Business Services".
               */
               // Get the permission of current user for the "parentList"
               foreach(SPRoleDefinition definition in parentList.AllRolesForCurrentUser)
               {
                   Console.WriteLine(definition.Name);
                   if( (definition.BasePermissions & SPBasePermissions.ApproveItems) != 0)
                   {
                       isApprover = true;
                       break;
                   }
               }        

                /* STEP4:
                    If the current logged in user has "Contribute" permissions, then we show an error message to the user.
                */

                // if user is NOT an approver show the error message
               if (!isApprover)
               {
                   properties.Cancel = true;
                   properties.ErrorMessage = "You dont have access to this operation because of your access rights.....";
               }
           }

           this.EnableEventFiring();
       }


 Cheers, 
--Aroh


Reference: 
Geek hubkey
Social MSDN SharePoint forum


No comments:

How to display Sharegate administrative dynamic reports via Power BI on SharePoint Online

After working in the SharePoint domain for a couple of years as SharePoint consultant , I am fortunate enough to help customers from man...