Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Moved validation method to sepreate utilities class. Added two new ex…
…tended classes and custom command patch to extend workflow without locking behavior to gutter.
  • Loading branch information
scVandal committed Aug 1, 2018
1 parent 570fb86 commit 21eb78a
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 47 deletions.
12 changes: 12 additions & 0 deletions App_Config/Include/SitecoreSolutions.Commands.config
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!--Custom Command Configuration Patch file-->
<configuration xmlns:x="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
<sitecore>
<commands>
<!--Extended ShowWorkflowCommand. Used by ExtendedWorkflowState.cs to allow for custom authentication to determine if item needs to be locked
for current user in order to execute workflow commands. -->
<command name="ss:extendedshowworkflowcommands"
type="SS.BaseConfig.Extensions.ShowWorkflowCommands.ExtendedShowWorkflowCommands,SS.BaseConfig" />
</commands>
</sitecore>
</configuration>
65 changes: 65 additions & 0 deletions Extensions/Gutters/ExtendedWorkflowState.cs
@@ -0,0 +1,65 @@
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.ContentEditor.Gutters;
using Sitecore.Workflows;

/// <summary>
/// This class is a straight extract-and-copy of the WorflowState class in Sitecore.Kernel under the namespace
/// Sitecore.Shell.Applications.ContentEditor.Gutters.WorkflowState.
/// There is one single change between this file and the base workflowState file, at line 61 , which calls a custom extendedShowWorkflowState
/// command that contains additional logic to check if user can execute workflow state without locking.
/// </summary>
/// <remarks>Don't forget to change namespace to your environment</remarks>
namespace SS.BaseConfig.Extensions.Gutters
{
public class ExtendedWorkflowState : GutterRenderer
{
/// <summary>
/// Determines whether this instance is visible and should be rendered in context menu.
/// </summary>
/// <returns>
/// <c>true</c> if this instance is visible; otherwise, <c>false</c>.
/// </returns>
public override bool IsVisible()
{
if (!Settings.Workflows.Enabled)
return false;
return base.IsVisible();
}

/// <summary>Gets the icon.</summary>
/// <param name="item">The item.</param>
/// <returns>The icon.</returns>
protected override GutterIconDescriptor GetIconDescriptor(Item item)
{
Assert.ArgumentNotNull((object)item, nameof(item));
string str1 = item[FieldIDs.Workflow];
string str2 = item[FieldIDs.WorkflowState];
if (!Settings.Workflows.Enabled || !item.Access.CanWrite())
return (GutterIconDescriptor)null;
if (string.IsNullOrEmpty(str1) || string.IsNullOrEmpty(str2))
return (GutterIconDescriptor)null;
IWorkflowProvider workflowProvider = item.Database.WorkflowProvider;
if (workflowProvider == null)
return (GutterIconDescriptor)null;
IWorkflow workflow = workflowProvider.GetWorkflow(item);
if (workflow == null)
return (GutterIconDescriptor)null;
Sitecore.Workflows.WorkflowState state = workflow.GetState(item);
if (state == null)
return (GutterIconDescriptor)null;
if (state.FinalState)
return (GutterIconDescriptor)null;
GutterIconDescriptor gutterIconDescriptor = new GutterIconDescriptor();
gutterIconDescriptor.Icon = state.Icon;
gutterIconDescriptor.Tooltip = state.DisplayName;
WorkflowCommand[] workflowCommandArray = WorkflowFilterer.FilterVisibleCommands(workflow.GetCommands(item), item);
if (workflowCommandArray != null && workflowCommandArray.Length != 0)
//Modify the event subscribed to the gutterIconDescriptor to call custom command, found at ExtendedShowWorkflowCommands.cs
gutterIconDescriptor.Click = "ss:extendedshowworkflowcommands(id=" + (object)item.ID + ",language=" + (object)item.Language + ",version=" + (object)item.Version + ",database=" + item.Database.Name + ")";
return gutterIconDescriptor;
}
}
}
74 changes: 74 additions & 0 deletions Extensions/ShowWorkflowCommands/ExtendedShowWorkflowCommands.cs
@@ -0,0 +1,74 @@
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Security.Accounts;
using Sitecore.Shell.Framework.CommandBuilders;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Workflows;
using System;
using System.Collections.Generic;

/// <summary>
/// This class is a extact-and-copy of the ShowWorkflowCommand in Sitecore.Kernel. This class contains a single modification to the menu.Add code
/// at line 68 that makes a call to Utilities.canUserRunCommandsWithoutLocking() method to check if context user meets the criteria set out by this method
/// to allow execution of workflow commands without locking. If they pass this check, the gutter workflow command buttons become active even without
/// locking the item.
/// </summary>

///<remarks>Don't forget to change Namespace to suit your environment!</remarks>
namespace SS.BaseConfig.Extensions.ShowWorkflowCommands
{
[Serializable]
public class ExtendedShowWorkflowCommands : Command
{
/// <summary>Queries the state of the command.</summary>
/// <param name="context">The context.</param>
/// <returns>The state of the command.</returns>
public override CommandState QueryState(CommandContext context)
{
if (!Settings.Workflows.Enabled)
return CommandState.Hidden;
return base.QueryState(context);
}

/// <summary>Executes the command in the specified context.</summary>
/// <param name="context">The context.</param>
public override void Execute(CommandContext context)
{
Assert.ArgumentNotNull((object)context, nameof(context));
string parameter1 = context.Parameters["database"];
string parameter2 = context.Parameters["id"];
string parameter3 = context.Parameters["language"];
string parameter4 = context.Parameters["version"];
Database database = Factory.GetDatabase(parameter1);
if (database == null)
return;
Item obj = database.GetItem(parameter2, Language.Parse(parameter3), Sitecore.Data.Version.Parse(parameter4));
if (obj == null)
return;
IWorkflow workflow = obj.Database.WorkflowProvider.GetWorkflow(obj);
if (workflow == null)
return;
WorkflowCommand[] workflowCommandArray = WorkflowFilterer.FilterVisibleCommands(workflow.GetCommands(obj), obj);
if (workflowCommandArray == null || workflowCommandArray.Length == 0)
return;
Menu menu = new Menu();
SheerResponse.DisableOutput();
foreach (WorkflowCommand command in workflowCommandArray)
{
string click = new WorkflowCommandBuilder(obj, workflow, command).ToString();
//Add new logical condition to call canUserRunCommandsWithoutEdit() in Utilities class to check if user has permissions to execute
//workflow commands without locking. The rest of the conditions are same as in default class
menu.Add("C" + command.CommandID, command.DisplayName, command.Icon, string.Empty, click, false, string.Empty, MenuItemType.Normal).Disabled
= !Utilities.canUserRunCommandsWithoutLocking() && !Context.User.IsAdministrator && !obj.Locking.HasLock() && Settings.RequireLockBeforeEditing;
}
SheerResponse.EnableOutput();
SheerResponse.ShowContextMenu(Context.ClientPage.ClientRequest.Control, "right", (Control)menu);
}
}
}
44 changes: 44 additions & 0 deletions Extensions/Utilities.cs
@@ -0,0 +1,44 @@
using Sitecore;
using Sitecore.Security.Accounts;
using System.Collections.Generic;

/// <remarks>Don't forget to change the Namespace to suit your environment!</remarks>
namespace SS.BaseConfig.Extensions
{
/// <summary>
/// Contains various generic and/or abstract utility methods to acomplish tasks in specific Extension code files
/// </summary>
public class Utilities
{
/// <summary>
/// Determines whether the current context user has the ability to execute workflow commands without locking the item
/// for editing. In its current implementation the class simply checks the current user against a list of roles that
/// shoudl have this permission. You can extend and expand this class to include all sorts of validation as desired.
/// </summary>
/// <returns>
/// true if user meets the cireteria set out by the class
/// </returns>
public static bool canUserRunCommandsWithoutLocking()
{
User user = Context.User;
//Define list of roles that are approved to have this access. Add the full name for your environment here
List<string> roleList = new List<string>
{
"sitecore\\Author", //This is the standard Author role provided with Sitecore
"sitecore\\anotherRoleHere" //This is a fake role just serving as an example!
};
//Iterate over each role in the list and check if user is a member of the role. If they are return true
foreach (string s in roleList)
{
if (user.IsInRole(s)) { return true; }
}
/// <remarks>
/// Add your own validation here. Maybe if a user is of a certain account. Or if they have edit rights to the item. Or if
/// their full name contains every vowel in the english langauge! Any validation goes!!!
/// </remarks>

//Return false if conditions aren't met, indicating user should not have the right to execute commands without locking item
return false;
}
}
}
@@ -1,20 +1,4 @@
/* <summary>
* This class is a standalone, extended copy of the WorkflowPanel class as defined in Sitecore.Client
* and makes minimal modifications to allow a user who meets certain role criteria (defined by you!) to
* execute Workflow Commands from the workflow panel without locking the item for editing.
*
* This is the way Sitecore worked prior to 8.1 and this class is a reversion to this functionality with the
* added benefit of allowing you to dole out this 'inline workflow command execute' ability as you desire.
*
* The extensiosn to this class are minimal: a new canUserRunCommandsWithoutEdit class is created which returns a
* Boolean value. This boolean value is used in line 62 in the flag4 definition to allow the workflowpanel to enable
* user interaction with the Workflow Panel buttons.
*
* You can modify the canUserRunCommandsWithoutEdit() method to include additional roles, or expand it even further
* to suite your needs when it comes to limiting this inline workflow command execution ability.
*/

using Sitecore;
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
Expand All @@ -29,10 +13,13 @@
using System.Collections.Generic;
using System.Web.UI;

//CHANGE THE NAMESPACE TO SUIT YOUR ENVIRONMENT!
namespace BaseConfig.Extensions
/// <summary>
/// This class is a straight extract-and-copy from Sitecore.Client's WorkflowPanel method. This extends class makes a single modification to
/// the flag4 boolean code at line 53, adding a call to Utilities.canUserRunCommandsWithoutLocking() method, which checks if the context user meets
/// the conditions outlined in the utilities method to execute workflow commands without locking the item.
/// </summary>
namespace SS.BaseConfig.Extensions.WorkflowPanel
{
/// <summary>Represents a WorkflowPanel.</summary>
public class ExtendedWorkflowPanel : RibbonPanel
{
/// <summary>The _check in item.</summary>
Expand Down Expand Up @@ -60,8 +47,10 @@ public override void Render(HtmlTextWriter output, Ribbon ribbon, Item button, C
bool flag1 = this.IsCommandEnabled("item:checkout", obj);
bool flag2 = ExtendedWorkflowPanel.CanShowCommands(obj, commands);
bool flag3 = this.IsCommandEnabled("item:checkin", obj);
//Add call to Utilities.canUserRunCommandsWithoutLocking() to validate user against custom criteria. If method returns true, this flag4 will be set
//to true and the workflow commands will be clickable even if item is not locked by user
bool flag4 = Context.User.IsAdministrator || obj.Locking.HasLock() || !Settings.RequireLockBeforeEditing ||
canUserRunCommandsWithoutEdit();
Utilities.canUserRunCommandsWithoutLocking();
this.RenderText(output, ExtendedWorkflowPanel.GetText(context.Items));
if (!(workflow != null | flag1 | flag2 | flag3))
return;
Expand Down Expand Up @@ -207,31 +196,5 @@ private bool IsCommandEnabled(string command, Item item)
return commandState == CommandState.Enabled;
return true;
}

/// <summary>
/// Determines whether the current context user has the ability to execute workflow commands without locking the item
/// for editing. In its current implementation the class simply checks the current user against a list of roles that
/// shoudl have this permission. You can extend and expand this class to include all sorts of validation as desired.
/// </summary>
/// <returns>
/// true if user meets the cireteria set out by the class
/// </returns>
private bool canUserRunCommandsWithoutEdit()
{
User user = Context.User;
//Define list of roles that are approved to have this access. Add the full name for your environment here
List<string> roleList = new List<string>
{
"sitecore\\Author", //This is the standard Author role provided with Sitecore
"sitecore\\anotherRoleHere" //This is a fake role just serving as an example!
};
//Iterate over each role in the list and check if user is a member of the role. If they are return true
foreach(string s in roleList)
{
if(user.IsInRole(s)) { return true; }
}
//Otherwise return false, indicating user should not have the right to execute commands without locking item
return false;
}
}
}

0 comments on commit 21eb78a

Please sign in to comment.