How can I remove «Reports» from the global menu?

Vote:
 

I would like «Reports» in the global menu to be visible for members of a specific user group.

Other users should not see «Reports».

How can that be done?

#221607
Apr 22, 2020 8:13
Vote:
 

I don't know if you can somehow replace the default MenuProvider to accomplish this, but if you don't mind a little hack, you could do it like this:

[MenuProvider]
public class CustomMenuProvider : IMenuProvider
{
    public IEnumerable<MenuItem> GetMenuItems()
    {
        if (!PrincipalInfo.Current.RoleList.Contains("ReportsRole"))
        {
            var hideMenuHack = new UrlMenuItem(
            "<span><style>.epi-navigation-global_cms_report { display:none !important }</style></span>",
            "/global/cms/edit",
            "javascript: return;"
            );

            return new MenuItem[] { hideMenuHack };
        }

        return new MenuItem[0];
    }
}
#221610
Apr 22, 2020 9:29
Vote:
 

Thanks Jørgen, almost...

#221614
Apr 22, 2020 9:53
Vote:
 

Ah, too bad, I even tested it - but not on the new (blue) menu.

#221616
Apr 22, 2020 10:00
Vote:
 

I checked out the new menu and it doesn't use the same class names as before, so the CSS hack wouldn't work anyway. 

I guess if you really need to fix it you could register a custom script in module.config, get all the menu items and hide the Reports item if the user doesn't have the required access (perhaps make a rest endpoint that the script can call to check it). 

#221623
Apr 22, 2020 11:39
Vote:
 

How about a less hacky method? 😀

You could implement a custom menu assembler and remove the report item as required:

[ServiceConfiguration(ServiceType = typeof(MenuAssembler), Lifecycle = ServiceInstanceScope.Singleton)]
public class CustomMenuAssembler : MenuAssembler
{
    public CustomMenuAssembler(IMenuProvider[] menuProviders, IServiceLocator container) : base(menuProviders,
        container)
    {
    }

    public override IEnumerable<MenuItem> GetMenuItems(string parentPath, int relativeDepth)
    {
        var menuItems = base.GetMenuItems(parentPath, relativeDepth).ToList();

        var reportItem =
            menuItems.SingleOrDefault(x => x.Path.Equals("/global/cms/report", StringComparison.Ordinal));

        if (reportItem == null)
        {
            return menuItems;
        }

        // Add user group check here
        menuItems.Remove(reportItem);

        return menuItems;
    }
}
#221627
Apr 22, 2020 14:12
Vote:
 

Thank you Jake! :-)

#221630
Apr 22, 2020 14:45
Vote:
 

I didn't get this part to work in an Alloy site:

[ServiceConfiguration(ServiceType = typeof(MenuAssembler), Lifecycle = ServiceInstanceScope.Singleton)]

So I registered it like this:

[InitializableModule]
public class DependencyResolverInitialization : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        context.ConfigurationComplete += (o, e) =>
        {
            context.Services.AddSingleton<MenuAssembler, LimitedReportsMenuAssembler>();
        };
    }
}

Any suggestion why the attribute did not work?

#221632
Apr 22, 2020 15:19
Vote:
 

Honestly, I like this better anyway.

At a guess, it's probably because under the hood Epi is using reflection to retrieve and register all the ServiceConfigurationAttributes. That means it would be getting registered twice and which ever gets registered last is going to be used, not sure what is deciding the order but your code solves the problem by ensuring the custom one is registered last.

That's my theory at least! 😉

#221633
Apr 22, 2020 16:03
Vote:
 

Never even heard of the MenuAssembler :D 

You learn something every day!

#221637
Apr 22, 2020 16:06
Vote:
 

Hi all,

I would add here that yes this fullfills the requirement of removing the menu item for reports if the logged in user is not in the defined group/role BUT if they know the Reports url they still can access the reports main view (default url: /EPiServer/CMS/Report/default.aspx, if UI url is not changed - but in all projects this ofcourse changed :D) and from there navigate to all the reports. If security audit is done - we should also limit the real access.

Simple base limitation would be in web.config to add a new location element:

<location path="EPiServer/CMS/Report">
  <system.web>
    <authorization>
      <allow roles="ReportViewers"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>

Naturally one would use the 'role' one has used in the code limiting the visibility of the Reports menu item.

Note! All the Episerver default reports use the base path of 'ui-url-here/cms/report' so the above access restriction works for those (including the menu.aspx creating the left menu in the reports view) but any custom reports in other locations would need their own restriction location element.

#222417
May 05, 2020 16:34
Vote:
 

Excellent point, Antti Alasvuo!

#222455
May 06, 2020 7:11
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.