8

Resolved

Reduce in NavigationManager doesn’t show menus build thru IMenuProvider

description

I have built a couple of menus using the following code:

public class MainMenu : IMenuProvider
{
public Localizer T { get; set; }

public void GetMenu(IContent menu, NavigationBuilder builder)
{
    builder.Add(T("Home"), "1",
        subMenu => subMenu.Url("~/"));

    builder.Add(T("Help"), "2",
        subMenu => subMenu.Url("~/help").Permission(StandardPermissions.AccessFrontEnd));
}
}

However, those menus only appear when admin user logon. That’s because Reduce method only analyzes three cases: When Debug is on (hasDebugShowAllMenuItems), when item.Content != null and when is Admin Menu. But those previously created menus thru IMenuProvider have item.Content set to null. My solution was to add a new condition:

// Handle custom menu (IMenuProvider)
item.Content == null && (!item.Permissions.Any() || item.Permissions.Any(x => _authorizationService.TryCheckAccess(x, _orchardServices.WorkContext.CurrentUser, null))) ||

Also this patch solves the problem when you implement INavigationProvider and use _navigationManager.BuildMenu("CustomMenuName").

comments

torp3d0 wrote Jan 28, 2013 at 7:38 AM

where im going to put this handller?

// Handle custom menu (IMenuProvider)
item.Content == null && (!item.Permissions.Any() || item.Permissions.Any(x => _authorizationService.TryCheckAccess(x, _orchardServices.WorkContext.CurrentUser, null))) ||


http://orchard.codeplex.com/workitem/19416 <--- here my problem

the menu shown only in admin user or site owner...

how to solve this one so that my menu shown to other user.

thanks

aletc1 wrote Jan 28, 2013 at 9:13 PM

You need to modify the method Reduce in file NavigationManager.cs located in src\orchard.web\core\navigation\services then recompile source code. This will solve your issue (#19416).

/// <summary>
/// Updates the items by checking for permissions
/// </summary>
private IEnumerable<MenuItem> Reduce(IEnumerable<MenuItem> items, bool isAdminMenu) {
var hasDebugShowAllMenuItems = _authorizationService.TryCheckAccess(Permission.Named("DebugShowAllMenuItems"), _orchardServices.WorkContext.CurrentUser, null);

foreach (var item in items) {
    if (
        // debug flag is on
        hasDebugShowAllMenuItems ||

        // Handle custom menu (IMenuProvider)
        item.Content == null && (!item.Permissions.Any() || item.Permissions.Any(x => _authorizationService.TryCheckAccess(x, _orchardServices.WorkContext.CurrentUser, null))) ||

        // a content item is linked and the user can view it
        item.Content != null && item.Permissions.Concat(new[] { Contents.Permissions.ViewContent }).Any(x => _authorizationService.TryCheckAccess(x, _orchardServices.WorkContext.CurrentUser, item.Content)) ||

        // it's the admin menu and permissions are effective
        isAdminMenu && (!item.Permissions.Any() || item.Permissions.Any(x => _authorizationService.TryCheckAccess(x, _orchardServices.WorkContext.CurrentUser, null))) ) {

        yield return new MenuItem {
            Items = Reduce(item.Items, isAdminMenu),
            Permissions = item.Permissions,
            Position = item.Position,
            RouteValues = item.RouteValues,
            LocalNav = item.LocalNav,
            Culture = item.Culture,
            Text = item.Text,
            IdHint = item.IdHint,
            Classes = item.Classes,
            Url = item.Url,
            LinkToFirstChild = item.LinkToFirstChild,
            Href = item.Href,
            Content = item.Content
        };
    }
}
}

torp3d0 wrote Jan 30, 2013 at 3:28 AM

thanks got it.

rodpl wrote May 3, 2013 at 11:09 AM

You can try such work around waiting for patch ...
    public class LoyaltyMenu : IMenuProvider
    {
        private const string AreaName = "Loyalty";

        private static readonly FakeMenuContent FakeContent = new FakeMenuContent();

        public LoyaltyMenu()
        {
            this.T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void GetMenu(IContent menu, NavigationBuilder builder)
        {
            this.BuildMenu(builder);
        }

        private void BuildMenu(NavigationBuilder menu)
        {
            menu.Add(
                this.T("Manage offers"),
                "1.100",
                item => item
                    .Action("Index", "ManageOffers", new { Area = AreaName })
                    .Content(FakeContent));
        }

        private class FakeMenuContent : IContent
        {
            private readonly ContentItem emptyContentItem = new ContentItem();

            public ContentItem ContentItem
            {
                get
                {
                    return this.emptyContentItem;
                }
            }

            public int Id
            {
                get
                {
                    return -1;
                }
            }
        }
    }

pszmyd wrote May 10, 2013 at 4:51 PM

Fixed in changeset ae9aa724e8be

sfmskywalker wrote Mar 28 at 1:28 AM

Fixed in changeset 57339d5606b33f45cfbda4b92c49201c95ae65fa