November Happy Hour will be moved to Thursday December 5th.

Mark Hall
May 16, 2018
  5274
(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
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog