Episerver has a powerful UI that makes it very easy for editors to create and edit content in an on-page and a drag and drop way. However I was recently talking to a customer who are going to have a larger editor estate (> 500 people) and wanted 2 types of editors. The first type are editors who are trained and are familiar with Episerver. These editors can use the UI as normal for creating and editing content.

The second type of editor is more interesting. They should only be able edit existing content, often only on a single page. These editors require a very cut down version of the Episerver UI with "super simple" editor functions. So this post describes how its possible to hide certain Episerver UI elements for certain groups of editors. 

Identifying the "restricted" users

First of all we need to identify our restricted users. For the code in the rest of this example we check on a role called "restrictedusers". This is a simple implementation that we can use to decide if a user is restricted or not but can be modified as necessary in your own implementation:

public interface IUserIsRestricted
{
    bool UserIsRestricted();
}

[ServiceConfiguration(typeof(IUserIsRestricted))]
public class RestrictedUser : IUserIsRestricted
{
    public bool UserIsRestricted()
    {
        //Any implementation you wish, this is for simplicity
        return HttpContext.Current.User.IsInRole("RestrictedUser");
    }
}

Removing UI components

Now we can start to look at removing UI components such as the sites tab, media and even the page tree. Fortunately it's possible to remove components with a simple IViewTransformer implementation:

[ViewTransformer]
public class RestrictedUserViewTransformer : IViewTransformer
{
    public int SortOrder
    {
        get { return int.MaxValue; }
    }
         
    public void TransformView(ICompositeView view, IPrincipal principal)
    {
        if (ServiceLocator.Current.GetInstance().UserIsRestricted())
        {
            List components = new List();
            BuildListRecursively(view.RootContainer, components);
            view.RootContainer.RemoveComponentsRecursive(components, false);
        }
    }

    private void BuildListRecursively(IContainer parentContainer, List components)
    {
        foreach (IComponent component in parentContainer.Components)
        {
            IContainer childContainer = component as IContainer;
            if (childContainer != null)
            {
                BuildListRecursively(childContainer, components);
            }
            else
            {
                if (component.DefinitionName != "EPiServer.Cms.Shell.UI.Components.WidgetSwitcher")
                {
                    // Remove everything apart from the main toolbar 
                    AddComponent(components, component.DefinitionName);
                }
            }
        }
    }

    private void AddComponent(List components, string definitionName)
    {
        ConfigurationComponentMatcher item = new ConfigurationComponentMatcher(definitionName);
        components.Add(item);
    }


    private class ConfigurationComponentMatcher : IComponentMatcher, IContainerMatcher
    {
        // Fields
        private readonly string _definitionName;

        // Methods
        public ConfigurationComponentMatcher(string definitionName)
        {
            this._definitionName = definitionName;
        }

        public bool MatchesComponent(IComponent component)
        {
            return string.Equals(this._definitionName, component.DefinitionName, StringComparison.OrdinalIgnoreCase);
        }

        public bool MatchesContainer(IContainer container)
        {
            return true;
        }
    }
}

This code removes all components in the UI apart from the content itself which is the "EPiServer.Cms.Shell.UI.Components.WidgetSwitcher" component. It's possible to decide which components you do/do not want to remove by the component name. All Episerver component names are prefixed with "EPiServer.Cms.Shell.UI.Components" and following table shows some of the built in components that ship with Episerver:

Component IDUI element
PageTreeComponent
SiteTreeComponent
Tasks
ProjectChangesComponent
RecentItems
ProjectModeToolbarComponent
Toolbar
SharedBlocksComponent
MediaComponent

It should be noted that if you remove all the components from a panel then the panel itself will disappear. For example if you remove the "SharedBlocksComponent" and "MediaComponent" (blocks and media) then the right hand pin-able panel will disappear.  

Removing the preview buttons (preview, channels etc)

It may be desirable not to remove the entire tool bar that sits about the content in the UI and only remove some of the buttons: 

To achieve this we can use a little Dojo and the Episerver profile. This module can hide tool bar buttons if the user is a restricted user. Create a file called CustomiseToolbar.js in /ClientResource/Scripts/CustomUI/

 [[dojo code]]

define([
        "dojo/_base/declare",
        "dojo/_base/lang",
        "dojo/topic",
        "dojo/when",
        "epi/dependency"
    ],
    function
    (
        declare,
        lang,
        topic,
        when,
        dependency
    ) {

        return declare([], {

            initialize: function () {

                this.inherited(arguments);

                // Check if the user is restricted using the profile (this is accessible client and server side)
                var profile = dependency.resolve("epi.shell.Profile");
                if (profile) {

                    // Profile returns a promise so we wait for this before checking the value
                    when(profile.get("restricteduser"), function (restricteduser) {
                        if (restricteduser === true) {
                            // Get the global command registry
                            var registry = dependency.resolve('epi.globalcommandregistry');
                            // Clear the toolbar -- these are the buttons at the top of the UI for previewing as 
                            // visitor groups etc. 
                            var newProviders = [];

                            // It's also possible to remove or use single items as below:

                            // The Add button plus access to the left/right pinnable areas
                            //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[0]);

                            // View options (view as visitor group, preview button)
                            //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[1]);

                            // Compare button
                            //newProviders.push(registry._mappings['epi.cms.globalToolbar'].providers[2]);

                            registry._mappings['epi.cms.globalToolbar'].providers = newProviders;
                        }
                    });
                }
            }
        });
    });

 Merge this in module.config to initialise the component:


  
    
      
    
  
  
    
      
    
  

You may have noticed we are using the Episerver Shell Profile. This is a common profile that can be used server and client side. To set up the profile server side we can use an Episerver initialisation module to set a value for "restricteduser" (note the implementation is just an example and your implementation will probably differ!

[InitializableModule]
[ModuleDependency(typeof (EPiServer.Web.InitializationModule))]
public class RestrictedUserInit : IInitializableHttpModule
{
    public void InitializeHttpEvents(HttpApplication application)
    {
        application.PostAuthenticateRequest += Application_PostAuthenticateRequest;
    }

    private void Application_PostAuthenticateRequest(object sender, EventArgs e)
    {
        //Assumes use of session. Better place for this check would be on the log  
        //in controller for your site (if not using the default log in page)
        if (HttpContext.Current.User.Identity.IsAuthenticated
            && HttpContext.Current.Session != null
            && HttpContext.Current.Session["restricteduser_run"] == null)
        {
            // We only need this code to run once
            HttpContext.Current.Session["restricteduser_run"] = true;

            const string restrictedUserKey = "restricteduser";
            var profileRepo = ServiceLocator.Current.GetInstance();
            var profile = profileRepo.GetOrCreateProfile(HttpContext.Current.User.Identity.Name);
            profile.Settings[restrictedUserKey] = true;
            // Saving to the profile allows us to access this value in the client side UI
            profileRepo.Save(profile);
        }
    }

    public void Initialize(InitializationEngine context) { }

    public void Uninitialize(InitializationEngine context) { }
}

Once all of this is complete its possible to remove different tool bar buttons. The index of the registry._mappings['epi.cms.globalToolbar'].providers items is as follows:

IndexUI element
[0] - The Add button plus access to the left/right pinnable areas
[1] -View options (view as visitor group, preview button)
[2] - Compare button
[3] - Notifications

The finished product

When all the changes above have been applied a user will see the following UI when the hit the Episerver button on a page:

As you can see its very simple, offering a highly simplified page editing experience plus a publish button.

Conclusion

Episerver has a powerful UI that very simple for users. However in scenarios where we want users to focus on a single task then its possible to simplify the UI even further to ensure editors can focus on what they do best: creating and editing content.

Have you done anything similar to this? Have you faced this solution in another way? I’d be happy to discuss in the comments below or on @davidknipe.


Comments

comments powered by Disqus