Mark Hall
May 16, 2018
  5357
(6 votes)

Hide Sites in Page Tree for editors without Create or Edit Access rights

Recently I was asked by a customer how they could hide sites in the page tree for users without edit access.  I thought this was easily done using access rights, but I was wroing as the content still shows but cannot be edited since everyone has read access.  After some googling I found this article which was for CMS 6R2.  I tried removing the everyone role read access, but that led to the none of the sites showing in the page tree. 

Next I tried the next forum post which led to this article.  The code below is a continuation of the code found on the blog post by Thomas Krantz.  Please note that this code only cares about pages so editors will still have access to commerce content, blocks, media, etc.  It is also required either Edit or Create access to show the tree.

using EPiServer.Cms.Shell.UI.Rest.ContentQuery;
using EPiServer.Core;
using EPiServer.Data.Dynamic;
using EPiServer.Filters;
using EPiServer.Security;
using EPiServer.ServiceLocation;
using EPiServer.Shell.ContentQuery;
using System.Collections.Generic;
using System.Linq;

namespace EPiServer.Reference.Commerce.Site.Infrastructure
{
    [ServiceConfiguration(typeof(IContentQuery))]
    public class MyGetChildrenQuery : GetChildrenQuery
    {
        private readonly IContentRepository _contentRepository;
        private readonly IContentQueryHelper _queryHelper;
        private readonly LanguageSelectorFactory _languageSelectorFactory;

        public MyGetChildrenQuery(IContentQueryHelper queryHelper, IContentRepository contentRepository, LanguageSelectorFactory languageSelectorFactory) 
            : base(queryHelper, contentRepository, languageSelectorFactory)
        {
            _contentRepository = contentRepository;
            _queryHelper = queryHelper;
            _languageSelectorFactory = languageSelectorFactory;
        }

        public override int Rank => 100; 

        protected override IEnumerable<IContent> GetContent(ContentQueryParameters parameters)
        {
            if (((parameters.References == null) || !parameters.References.Any()) && ContentReference.IsNullOrEmpty(parameters.ReferenceId))
            {
                return Enumerable.Empty<IContent>();
            }

            var selector = _languageSelectorFactory.AutoDetect(true);
            IContent content = null;

            if (!ContentReference.IsNullOrEmpty(parameters.ReferenceId))
            {
                content = _contentRepository.Get<IContent>(parameters.ReferenceId) as PageData;
                if (content == null)
                {
                    return base.GetContent(parameters);
                }
                if (content.ContentLink.ID == 1 || (FilterAccess.QueryDistinctAccessEdit(content, AccessLevel.Edit) || FilterAccess.QueryDistinctAccessEdit(content, AccessLevel.Create)))
                {
                    return GetChildren(parameters, parameters.ReferenceId, selector);
                }
                return Enumerable.Empty<IContent>();
            }

            var filteredContent = new List<IContent>();
            foreach(var link in parameters.References.ToList())
            {
                content = _contentRepository.Get<IContent>(link) as PageData;
                if (content == null)
                {
                    filteredContent.AddRange(base.GetContent(parameters));
                    continue;
                }
                if (!FilterAccess.QueryDistinctAccessEdit(content, AccessLevel.Edit) || !FilterAccess.QueryDistinctAccessEdit(content, AccessLevel.Create))
                {
                    continue;
                }
                filteredContent.AddRange(GetChildren(parameters, parameters.ReferenceId, selector));
            }
            return filteredContent;
        }

        private IEnumerable<IContent> GetChildren(ContentQueryParameters parameters, ContentReference parentId, LanguageSelector selector)
        {
            IEnumerable<IContent> children = null;

            if (parameters.TypeIdentifiers != null && parameters.TypeIdentifiers.Any())
            {
                // Get by type and concatenate into one list
                children =
                    parameters.TypeIdentifiers.Select(i => TypeResolver.GetType(i, false))
                        .Where(type => type != null)
                        .SelectMany(type => GetChildrenByType(type, parentId, selector))
                        .Distinct()
                        .Where(x => FilterAccess.QueryDistinctAccessEdit(x, AccessLevel.Edit) || FilterAccess.QueryDistinctAccessEdit(x, AccessLevel.Create));
            }
            else
            {
                children = _contentRepository.GetChildren<IContent>(parentId, selector)
                    .Where(x => FilterAccess.QueryDistinctAccessEdit(x, AccessLevel.Edit) || FilterAccess.QueryDistinctAccessEdit(x, AccessLevel.Create)); ;
            }

            return (children ?? Enumerable.Empty<IContent>());
        }
    }
}

Here is how the access rights or setup for the site in questions.

Image AccessRights.png

Here is how the user permissions has been setup.

Image UserPermissions.png

Here is the site with administrator access.

Image Adminsitator.png

Here is the site with just site1 access.

Image Site1.png

May 16, 2018

Comments

Niklas Lord
Niklas Lord May 30, 2018 10:09 AM

Nice addition to the older solution. Great job!

Though it still have a problem I've been trying to solve before. What happens if you have no creat/edit access on a page. But you have that access on a child or a child deeper down in the tree.

Example:

Start = RCU

--Page A = R

----Page B = RCU

In that case A and B should be visible and A should be read only. With this solution A and B is hidden :-S

I guess you could query access down the tree but how will that affect the performance?

Andrea Sedlacek
Andrea Sedlacek Jun 6, 2018 11:40 PM

This is great!

Please login to comment.
Latest blogs
Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

Daniel Isaacs | Dec 22, 2024 | Syndicated blog

Increase timeout for long running SQL queries using SQL addon

Learn how to increase the timeout for long running SQL queries using the SQL addon.

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Overriding the help text for the Name property in Optimizely CMS

I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Resize Images on the Fly with Optimizely DXP's New CDN Feature

With the latest release, you can now resize images on demand using the Content Delivery Network (CDN). This means no more storing multiple versions...

Satata Satez | Dec 19, 2024

Simplify Optimizely CMS Configuration with JSON Schema

Optimizely CMS is a powerful and versatile platform for content management, offering extensive configuration options that allow developers to...

Hieu Nguyen | Dec 19, 2024

Useful Optimizely CMS Web Components

A list of useful Optimizely CMS components that can be used in add-ons.

Bartosz Sekula | Dec 18, 2024 | Syndicated blog