Question

I am working with SharePoint 2013 and a document library.

After numerous attempts at trying to coax the 2013 workflow process into doing what I needed, I gave up and resorted to a 2010 workflow.

This workflow is triggered by a change in the document, and runs through an approval process, which results in either the content approval or rejection of the document.

During this process, I don't want users editing the document and changing it.

Edit: The workflow, itself, needs to change fields in the item during its process, so it has to be able to check-in / check-out and make changes to the item. (Added 16/12/2014)

The library this workflow is associated with has required check-in / check-out as well as content approval.

What I've tried:

  • The workflow checks out the document and only checks it in when it's finished.
    Issue - the workflow doesn't realise it has the document checked out, thinks there's a lock on it, and stops the process until the document is checked in again.

  • Impersonation step to change the permissions to readonly on the item.
    Issue: not only did the permissions stay the same, but I realised by doing that (if it had worked) I would prevent my valid users seeing the draft they were being asked to approve.

  • Event receiver to check if anyone other than the workflow is checking the document out, and stopping them.
    Issue: the workflow runs under the user who starts it (e.g. the user who requests the document be published), and not a dedicated workflow account (or even the system account), so I couldn't work out which user account to allow the checkout for.

  • Cancelling the workflow on change (as an almost last resort).
    Issue: the workflow itself changes the item by changing properties as it runs. This causes an error, and the workflow just stops, instead of ending the task process, as it's supposed to.

Is there any method of allowing the workflow to do what it needs to, but stopping the users changing the document while the workflow is in progress? Any ideas would be fantastic.

Was it helpful?

Solution

The following may not be best practice, and I appreciate that it doesn't completely solve my issue, but I wanted to write down what I did anyway, in case it helps someone else.

So, I am using:

C# code and the ItemCheckingOut event to check for active workflows on the relevant item. It looks for the word "approval" in the name (as all my approval workflows will have "approval" in their name), and if that's true, plus the workflow AuthorUser.ID doesn't match the properties.CurrentUserId, then it prevents the checkout.

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

    try
    {
        int currentUserId = properties.CurrentUserId;

        // Get the currently running workflows on the list item.
        SPWorkflowCollection col = properties.Site.WorkflowManager.GetItemActiveWorkflows(properties.ListItem);

        if (col.Count > 0)
        {
            foreach (SPWorkflow wf in col)
            {
                // If the workflow is one of the approvals (and therefore should be named as such), 
                // and the initiator of the workflow (that's what the property AuthorUser is) doesn't match the current user,
                // prevent the user checking the item out.
                // If it does match, allow the checkout, as it's likely to be the workflow checking the item out.
                if ((properties.List.WorkflowAssociations[wf.AssociationId].Name.ToLower().Contains("approval")) && (wf.AuthorUser.ID != currentUserId))
                {
                    // Need to cancel the checkout as the workflow is running and the document shouldn't be editable.
                    properties.ErrorMessage = "The document is currently going through the Approval process. During this process, the document is not available for editing.";
                    properties.Status = SPEventReceiverStatus.CancelWithError;
                }
            }
        }
    }
    catch (Exception ex)
    {
        properties.Status = SPEventReceiverStatus.CancelWithError;
        properties.ErrorMessage = ex.Message;
        return;
    }
}

Caveats

  • I am working on the basis that the initiator of the workflow (which is held in the AuthorUser.ID) needs to check out and change the item, so I need to let that user check it out. I realise this doesn't stop the genuine user from checking out the document again, so I will need to revisit this at some point.
  • I have hardcoded the word, "approval", into the code, which is never a good thing to do. It works here, as our processes dictate naming conventions, and these workflows will follow a naming convention that contains the word, "approval", but that doesn't make it a good thing to do.

Other possibilities

Through talks with other SharePoint people, another solution may be workable, and I may try it in the future. Again, I'm writing it here in case it's of use to someone else:

  • As well as the main document library you're using, create another library with readonly permissions.

  • When the approval workflow kicks off, copy the correct version of the draft document over to the readonly library, and get your approvers to look at the document there. The existing document becomes readonly, so even your editors can't see the draft in the proper library.

  • Initial reviewers and final approvers (or however your library approval process is setup) can all see the correct document in the temp library, but can't make any changes.

  • Once either approved or rejected, the item in the temp library can be deleted, normal permissions reinstated on the proper library, and the approval status updated on the correct item in the proper library.

I hope this helps someone else who is looking for this sort of solution, even if it just gives them some ideas of what they might be able to do to accomplish what they need.

OTHER TIPS

How about the workflow setting a hidden status field to 'in progress' and an event handler not allowing any changes when the status field has this value?

When the workflow is done, it resets the status field to the initial value (whatever you choose it to be).

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top