• Skip to main content
  • Skip to primary sidebar

Technical Notes Of
Ehi Kioya

Technical Notes Of Ehi Kioya

  • About
  • Contact
MENUMENU
  • Blog Home
  • AWS, Azure, Cloud
  • Backend (Server-Side)
  • Frontend (Client-Side)
  • SharePoint
  • Tools & Resources
    • CM/IN Ruler
    • URL Decoder
    • Text Hasher
    • Word Count
    • IP Lookup
  • Linux & Servers
  • Zero Code Tech
  • WordPress
  • Musings
  • More
    Categories
    • Cloud
    • Server-Side
    • Front-End
    • SharePoint
    • Tools
    • Linux
    • Zero Code
    • WordPress
    • Musings
Home » Backend (Server-Side) » SharePoint Approval Workflow Enhancement

SharePoint Approval Workflow Enhancement

By Ehi Kioya Leave a Comment

Approval Workflow Problem

When the out of the box SharePoint approval workflow publishes an item, it sets the “Modified by” field as “System Account” instead of setting this to the actual user who did the approval.

One way around this could be to add another column to hold the correct Modified by user instead of the out of the box Modified by column. But since not all clients will be satisfied with this approach, I will explain another way here.

The Solution

We will solve this problem by publishing the item with custom code instead of as part of the out-of-the-box SharePoint approval workflow process. But for our custom code to work, when creating the workflow association, we need to ensure the following:

  • Leave the option – “Start this workflow to approve publishing a major version of an item” unselected.
  • Leave the option – “Update the approval status after the workflow is completed (use this workflow to control content approval)” unselected too.

And now for the code…

We create a web scoped feature and add an event receiver to hold our code. Our event receiver will override the WorkflowCompleted method. As you may know, an Elements.xml file is automatically generated for us based on the settings we select when creating the event receiver.

For reference, here’s the Elements.xml code (Notice that the ListTemplateId is 100. The ListTemplateId specifies the index of the list template to which the event receiver applies. For a list of the default list template types, see SPListTemplateType).

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="100">
      <Receiver>
        <Name>ApprovalEnhancementsWorkflowCompleted</Name>
        <Type>WorkflowCompleted</Type>
        <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
        <Class>ApprovalEnhancements.ApprovalEnhancements.ApprovalEnhancements</Class>
        <SequenceNumber>10000</SequenceNumber>
      </Receiver>
  </Receivers>
</Elements>

The C# Code

Here’s the full code for this fix. The entry point is the overridden WorkflowCompleted method.

using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;

namespace ApprovalEnhancements.ApprovalEnhancements
{
    /// <summary>
    /// List Workflow Events
    /// </summary>
    public class ApprovalEnhancements : SPWorkflowEventReceiver
    {
        private string editor = "";

        /// <summary>
        /// A workflow was completed.
        /// </summary>
        public override void WorkflowCompleted(SPWorkflowEventProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(properties.WebUrl))
                {
                    using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
                    {
                        SPListItem workflowHistoryItem = GetWorkflowHistoryItem(web, properties);
                        if (workflowHistoryItem != null)
                        {
                            SPListItem item = GetItemForThisWorkflow(web, workflowHistoryItem, properties);
                            editor = item[SPBuiltInFieldId.Editor].ToString();
                        }
                    }
                }
            });
            base.WorkflowCompleted(properties);
            PublishItemBasedOnWorkflowStatus(properties);
        }

        private SPListItem GetWorkflowHistoryItem(SPWeb web, SPWorkflowEventProperties properties)
        {
            string caml = string.Format(@"<Where>
                                              <And>
                                                 <Eq>
                                                    <FieldRef Name='WorkflowInstance' />
                                                    <Value Type='Text'>{0}</Value>
                                                 </Eq>
                                                 <Eq>
                                                    <FieldRef Name='Event' />
                                                    <Value Type='WorkflowEventType'>2</Value>
                                                 </Eq>
                                              </And>
                                           </Where>", properties.InstanceId.ToString("B"));
            SPList workflowHistory = web.Lists["Workflow History"];
            SPQuery query = new SPQuery();
            query.Query = caml;
            SPListItemCollection items = workflowHistory.GetItems(query);
            if (items.Count >= 1)
            {
                return items[0];
            }
            return null;
        }

        private SPListItem GetItemForThisWorkflow(SPWeb web, SPListItem workflowHistoryItem, SPWorkflowEventProperties properties)
        {
            int itemId = Convert.ToInt32(workflowHistoryItem["ows_Item"].ToString());
            Guid itemListGuid = new Guid(workflowHistoryItem["ows_List"].ToString());

            SPList itemParentList = web.Lists[itemListGuid];
            SPListItem item = itemParentList.GetItemById(itemId);

            return item;
        }

        private string GetStatusOfRuningWorkflow(SPListItem item, string workflowAssociationName)
        {
            SPWorkflow wf = item.Workflows[0]; // assume single workflow
            if (wf != null && wf.Tasks != null && wf.Tasks.Count > 0)
            {
                SPWorkflowTask task = wf.Tasks[wf.Tasks.Count - 1]; // analyze last task only

                if (task[SPBuiltInFieldId.TaskStatus].ToString() == "Completed")
                {
                    string workflowOutcome = task[SPBuiltInFieldId.WorkflowOutcome].ToString();
                    if (workflowOutcome.IndexOf("Approved") >= 0)
                        return "Approved";
                    else if (workflowOutcome.IndexOf("Rejected") >= 0)
                        return "Rejected";
                }
                return task[SPBuiltInFieldId.TaskStatus].ToString();
            }
            return "";
        }

        private void MarkItemApproveOrRejectBasedWorkflowStatus(SPListItem item, SPWeb web, string associationName, SPWorkflowEventProperties properties)
        {
            string status = GetStatusOfRuningWorkflow(item, associationName);

            //we are only interested in OUR WORKFLOW ASSOCIATION (i.e. configured in Settings List)
            //if it is different, then it returns empty string
            if (string.IsNullOrEmpty(status))
                return;

            item.ModerationInformation.Status = SPModerationStatusType.Denied;
            if (status.Equals("Approved"))
            {
                item.ModerationInformation.Status = SPModerationStatusType.Approved;
            }

            item[SPBuiltInFieldId.Editor] = editor;
            item.UpdateOverwriteVersion();

            if (status.Equals("Rejected"))
            {
                SPWorkflow wf = item.Workflows[0];
                SPWorkflowTask task = wf.Tasks[wf.Tasks.Count - 1];
                if (task["PercentComplete"].ToString() != "1")
                {
                    task["Status"] = "Canceled";
                    task["PercentComplete"] = 1;
                    web.AllowUnsafeUpdates = true;
                    task.Update();
                }
                SPWorkflowManager.CancelWorkflow(wf);
            }
        }

        private void PublishItemBasedOnWorkflowStatus(SPWorkflowEventProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(properties.WebUrl))
                {
                    using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
                    {
                        SPListItem workflowHistoryItem = GetWorkflowHistoryItem(web, properties);
                        if (workflowHistoryItem == null)
                        {
                            return;
                        }

                        SPListItem item = GetItemForThisWorkflow(web, workflowHistoryItem, properties);

                        //Provide association name so that it can ONLY approve item of that workflow
                        string associationName = "Site Info Approval";
                        MarkItemApproveOrRejectBasedWorkflowStatus(item, web, associationName, properties);
                    }
                }
            });
        }
    }
}

Found this article valuable? Want to show your appreciation? Here are some options:

  1. Spread the word! Use these buttons to share this link on your favorite social media sites.
  2. Help me share this on . . .

    • Facebook
    • Twitter
    • LinkedIn
    • Reddit
    • Tumblr
    • Pinterest
    • Pocket
    • Telegram
    • WhatsApp
    • Skype
  3. Sign up to join my audience and receive email notifications when I publish new content.
  4. Contribute by adding a comment using the comments section below.
  5. Follow me on Twitter, LinkedIn, and Facebook.

Related

Filed Under: Backend (Server-Side), SharePoint Tagged With: Programming, SharePoint

About Ehi Kioya

I am a Toronto-based Software Engineer. I run this website as part hobby and part business.

To share your thoughts or get help with any of my posts, please drop a comment at the appropriate link.

You can contact me using the form on this page. I'm also on Twitter, LinkedIn, and Facebook.

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Primary Sidebar

23,571
Followers
Follow
30,000
Connections
Connect
14,568
Page Fans
Like
  • Recently   Popular   Posts   &   Pages
  • Actual Size Online Ruler Actual Size Online Ruler
    I created this page to measure your screen resolution and produce an online ruler of actual size. It's powered with JavaScript and HTML5.
  • Fix For “Function create_function() is deprecated” In PHP 7.2 Fix For "Function create_function() is deprecated" In PHP 7.2
    As of PHP 7.2 create_function() has been deprecated because it uses eval(). You should replace it with an anonymous function instead.
  • How To Change A SharePoint List Or Library URL How To Change A SharePoint List Or Library URL
    All versions of the SharePoint user interface provide an option to change the title (or display name) of a list or library. Changing SharePoint library URL (or internal name), however, is not exactly very intuitive. We will discuss the process in this article.
  • About
  • Contact

© 2022   ·   Ehi Kioya   ·   All Rights Reserved
Privacy Policy