Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#8752: Hide/show menu items on the frond-end #8753

Open
wants to merge 2 commits into
base: 1.10.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 78 additions & 17 deletions src/Orchard.Web/Core/Contents/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Reflection;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.UI.WebControls;
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
Expand All @@ -12,7 +14,11 @@
using Orchard.Core.Containers.Models;
using Orchard.Core.Contents.Settings;
using Orchard.Core.Contents.ViewModels;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.Services;
using Orchard.Data;
using Orchard.Data.Bags;
using Orchard.Environment;
using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Logging;
Expand All @@ -32,21 +38,24 @@ public class AdminController : ContentControllerBase, IUpdateModel {
private readonly ISiteService _siteService;
private readonly ICultureManager _cultureManager;
private readonly ICultureFilter _cultureFilter;
private readonly ISignals _signals;

public AdminController(
IOrchardServices orchardServices,
IContentDefinitionManager contentDefinitionManager,
ISiteService siteService,
ICultureManager cultureManager,
ICultureFilter cultureFilter) : base(orchardServices.ContentManager) {
ICultureFilter cultureFilter,
ISignals signals
) : base(orchardServices.ContentManager) {
Services = orchardServices;
_contentManager = orchardServices.ContentManager;
_transactionManager = orchardServices.TransactionManager;
_contentDefinitionManager = contentDefinitionManager;
_siteService = siteService;
_cultureManager = cultureManager;
_cultureFilter = cultureFilter;

_signals = signals;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
Shape = orchardServices.New;
Expand Down Expand Up @@ -394,31 +403,27 @@ public class AdminController : ContentControllerBase, IUpdateModel {

[HttpPost]
public ActionResult Clone(int id, string returnUrl) {
var contentItem = _contentManager.GetLatest(id);

if (contentItem == null)
return HttpNotFound();
var originalContentItem = _contentManager.GetLatest(id);

if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Couldn't clone content")))
if (!Services.Authorizer.Authorize(Permissions.ViewContent, originalContentItem, T("Couldn't open original content")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why these permissions are changed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We started from a fork version of LaserOrchard which already has these changes, it is a part of code that I did not write but which I had to integrate to remain aligned with the version we started from. Ours mod is just a proposal, which unfortunately integrates changes that were not made by us, if too different from the code, as far as I'm concerned it can be rejected entirely

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are from the dev branch.

return new HttpUnauthorizedResult();

// pass a dummy content to the authorization check to check for "own" variations
var dummyContent = _contentManager.New(contentItem.ContentType);
var dummyContent = _contentManager.New(originalContentItem.ContentType);

if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content.")))
if (!Services.Authorizer.Authorize(Permissions.CreateContent, dummyContent, T("Couldn't create clone content")))
return new HttpUnauthorizedResult();

try {
Services.ContentManager.Clone(contentItem);
var cloneContentItem = _contentManager.Clone(originalContentItem);

Services.Notifier.Information(T("Successfully cloned. The clone was saved as a draft."));
if (string.IsNullOrWhiteSpace(returnUrl)) {
var adminRouteValues = _contentManager.GetItemMetadata(cloneContentItem).AdminRouteValues;
return RedirectToRoute(adminRouteValues);
}
catch (InvalidOperationException) {
Services.Notifier.Warning(T("Could not clone the content item."));
else {
return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}

Services.Notifier.Information(T("Successfully cloned. The clone was saved as a draft."));

return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}

[HttpPost]
Expand Down Expand Up @@ -477,6 +482,60 @@ public class AdminController : ContentControllerBase, IUpdateModel {
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}

/// <summary>
/// Set VisibleAtFrontEnd flag for menuPart
/// </summary>
/// <param name="menu">The menu item</param>
/// <param name="value">Show->true or Hide->false</param>
private void VisibleAtFrontEnd(MenuPart menu, Boolean value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method be here? It's working on MenuPart, but this controller is the one for ContentItems

//var menuItems = _contentManager
// .Query<MenuPart, MenuPartRecord>()
// .Where(x => x.MenuId == menu.Menu.Id)
// .List().Where(x => x.MenuPosition.StartsWith(menu.MenuPosition + "."))
// .Select(x => x.As<MenuPart>())
// .ToList();
//foreach (var menuItem in menuItems.Concat(new[] { menu })) {
// menuItem.VisibleAtFrontEnd = value;
//}
menu.VisibleAtFrontEnd = value;
//Trigger the change of NavigationContentItems in modules that cache this type of content
_signals.Trigger("NavigationContentItems.Changed");
}

/// <summary>
/// Set VisibleAtFrontEnd to false on content's menuPart (for itself not for its children)
/// </summary>
/// <param name="id">ContentItem Id</param>
/// <param name="returnUrl">return Url</param>
/// <returns></returns>
[HttpPost]
public ActionResult Hide(int id, string returnUrl) {
var contentItem = _contentManager.Get(id, VersionOptions.Latest);
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't edit content")))
return new HttpUnauthorizedResult();
MenuPart menuPart = contentItem.As<MenuPart>();
if (menuPart != null)
VisibleAtFrontEnd(menuPart, false);
return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}

/// <summary>
/// Set VisibleAtFrontEnd to true on content's menuPart (for itself not for its children)
/// </summary>
/// <param name="id"></param>
/// <param name="returnUrl"></param>
/// <returns></returns>
[HttpPost]
public ActionResult Show(int id, string returnUrl) {
var contentItem = _contentManager.Get(id, VersionOptions.Latest);
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't edit content")))
return new HttpUnauthorizedResult();
MenuPart menuPart = contentItem.As<MenuPart>();
if (menuPart != null)
VisibleAtFrontEnd(menuPart, true);
return this.RedirectLocal(returnUrl, () => RedirectToAction("List"));
}
}

[Obsolete("Use Orchard.Mvc.FormValueRequiredAttribute instead.")]
Expand All @@ -492,4 +551,6 @@ public class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
return !string.IsNullOrEmpty(value);
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Orchard.Core.Contents.Settings;
using Orchard.Data;
using System.Web.Routing;
using Orchard.Time;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove


namespace Orchard.Core.Navigation.Controllers {
[ValidateInput(false)]
Expand Down Expand Up @@ -129,6 +130,7 @@ public class AdminController : Controller, IUpdateModel {
IsMenuItem = menuPart.Is<MenuItemPart>(),
Text = menuPart.MenuText,
Position = menuPart.MenuPosition,
VisibleAtFrontEnd = menuPart.VisibleAtFrontEnd,
Url = menuPart.Is<MenuItemPart>()
? menuPart.As<MenuItemPart>().Url
: _navigationManager.GetUrl(null, Services.ContentManager.GetItemMetadata(menuPart).DisplayRouteValues),
Expand Down Expand Up @@ -248,6 +250,8 @@ public class AdminController : Controller, IUpdateModel {
return View(model);
}



[HttpPost, ActionName("Edit")]
[Mvc.FormValueRequired("submit.Save")]
public ActionResult EditPOST(int id, string returnUrl) {
Expand Down Expand Up @@ -295,5 +299,6 @@ public class AdminController : Controller, IUpdateModel {

return this.RedirectLocal(returnUrl, () => RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } }));
}

}
}
12 changes: 11 additions & 1 deletion src/Orchard.Web/Core/Navigation/Drivers/MenuPartDriver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Navigation.Models;
Expand Down Expand Up @@ -36,6 +37,7 @@ public class MenuPartDriver : ContentPartDriver<MenuPart> {
}
}


protected override DriverResult Editor(MenuPart part, dynamic shapeHelper) {
var allowedMenus = _menuService.GetMenus().Where(menu => _authorizationService.TryCheckAccess(Permissions.ManageMenus, _orchardServices.WorkContext.CurrentUser, menu)).ToList();

Expand All @@ -48,6 +50,7 @@ public class MenuPartDriver : ContentPartDriver<MenuPart> {
ContentItem = part.ContentItem,
Menus = allowedMenus,
OnMenu = part.Menu != null,
VisibleAtFrontEnd = part.Menu != null ? part.VisibleAtFrontEnd : true,
MenuText = part.MenuText
};

Expand All @@ -64,6 +67,7 @@ public class MenuPartDriver : ContentPartDriver<MenuPart> {
if (!_authorizationService.TryCheckAccess(Permissions.ManageMenus, _orchardServices.WorkContext.CurrentUser, menu))
return null;

part.VisibleAtFrontEnd = model.VisibleAtFrontEnd;
part.MenuText = model.MenuText;
part.Menu = menu;

Expand Down Expand Up @@ -93,6 +97,11 @@ public class MenuPartDriver : ContentPartDriver<MenuPart> {
part.MenuPosition = position
);

context.ImportAttribute(part.PartDefinition.Name, "VisibleAtFrontEnd", visibleAtFrontEnd =>
part.VisibleAtFrontEnd = Boolean.Parse(visibleAtFrontEnd)
);


context.ImportAttribute(part.PartDefinition.Name, "Menu", menuIdentity => {
var menu = context.GetItemFromSession(menuIdentity);
if (menu != null) {
Expand All @@ -113,6 +122,7 @@ public class MenuPartDriver : ContentPartDriver<MenuPart> {

context.Element(part.PartDefinition.Name).SetAttributeValue("MenuText", part.MenuText);
context.Element(part.PartDefinition.Name).SetAttributeValue("MenuPosition", part.MenuPosition);
context.Element(part.PartDefinition.Name).SetAttributeValue("VisibleAtFrontEnd", part.VisibleAtFrontEnd);
}
}
}
4 changes: 3 additions & 1 deletion src/Orchard.Web/Core/Navigation/Handlers/MenuPartHandler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Contents.Settings;
using Orchard.Core.Navigation.Models;
using Orchard.Data;

Expand All @@ -22,8 +24,8 @@ IContentManager contentManager
});

OnActivated<MenuPart>(PropertySetHandlers);
}

}
protected void PropertySetHandlers(ActivatedContentContext context, MenuPart menuPart) {
menuPart.MenuField.Setter(menu => {
if (menu == null || menu.ContentItem == null) {
Expand Down
13 changes: 12 additions & 1 deletion src/Orchard.Web/Core/Navigation/Migrations.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Orchard.ContentManagement.MetaData;
using System;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data.Migration;

Expand Down Expand Up @@ -185,5 +186,15 @@ public class Migrations : DataMigrationImpl {

return 7;
}

/// <summary>
/// Manage visibility of menuItem in frontEnd (default is true)
/// </summary>
/// <returns></returns>
public int UpdateFrom7() {
SchemaBuilder
.AlterTable("MenuPartRecord", table => table.AddColumn<bool>("VisibleAtFrontEnd", c => c.WithDefault(true)));
return 8;
}
}
}
1 change: 1 addition & 0 deletions src/Orchard.Web/Core/Navigation/Models/AdminMenuPart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ public class AdminMenuPart : ContentPart<AdminMenuPartRecord> {
get { return Record.AdminMenuPosition; }
set { Record.AdminMenuPosition = value; }
}

}
}
9 changes: 8 additions & 1 deletion src/Orchard.Web/Core/Navigation/Models/MenuPart.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Utilities;

Expand All @@ -23,5 +24,11 @@ public class MenuPart : ContentPart<MenuPartRecord> {
get { return Record.MenuPosition; }
set { Record.MenuPosition = value; }
}


public Boolean VisibleAtFrontEnd {
get { return Record.VisibleAtFrontEnd; }
set { Record.VisibleAtFrontEnd = value; }
}
}
}
4 changes: 3 additions & 1 deletion src/Orchard.Web/Core/Navigation/Models/MenuPartRecord.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement.Records;

namespace Orchard.Core.Navigation.Models {
Expand All @@ -9,5 +10,6 @@ public class MenuPartRecord : ContentPartRecord {
public virtual string MenuText { get; set; }
public virtual string MenuPosition { get; set; }
public virtual int MenuId { get; set; }
public virtual Boolean VisibleAtFrontEnd { get; set; }
}
}
21 changes: 19 additions & 2 deletions src/Orchard.Web/Core/Navigation/Services/DefaultMenuProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
using Orchard.Core.Navigation.Models;
using Orchard.Localization;
using Orchard.UI.Navigation;
using System.Collections;
using System.Linq;

namespace Orchard.Core.Navigation.Services {
public class DefaultMenuProvider : IMenuProvider {
private readonly IContentManager _contentManager;

public DefaultMenuProvider(IContentManager contentManager) {
_contentManager = contentManager;

_menuPartsMemory = new Dictionary<int, IEnumerable<MenuPart>>();
}

Expand All @@ -27,7 +28,23 @@ public class DefaultMenuProvider : IMenuProvider {
.Where(x => x.MenuId == menu.Id)
.List();
}
var menuParts = _menuPartsMemory[menu.Id];
var menuParts = _menuPartsMemory[menu.Id].ToList<MenuPart>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToList is unnecessary. Change the type of the dictionary instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless you think the enumeration is executing the query again.


//List of hidden items
var menuPartsHidden = _contentManager
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The menus are already loaded from database, why do another query? You can just filter in Linq.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried but the code didn't return the list I expected, this is the committed code I added in my version

        //An attempt to optimize the code above but unsuccessful
        //var menuParts = _contentManager
        //    .Query<MenuPart, MenuPartRecord>()
        //    .Where(x => x.MenuId == menu.Id && x.VisibleAtFrontEnd && !_contentManager
        //    .Query<MenuPart, MenuPartRecord>()
        //    .Where(x => x.MenuId == menu.Id && !x.VisibleAtFrontEnd)
        //    .List().Where(w => x.MenuPosition.StartsWith(w.MenuPosition)).Any())
        //    .List().ToList();

.Query<MenuPart, MenuPartRecord>()
.Where(x => x.MenuId == menu.Id && !x.VisibleAtFrontEnd)
.List();

//Removing from menuList the items with VisibleAtFrontEnd set to false
foreach (var itemHidden in menuPartsHidden) {
//Copy the list
MenuPart[] menuParts1 = new MenuPart[menuParts.Count];
menuParts.CopyTo(menuParts1);
foreach (var item in menuParts1)
if (item.MenuPosition.StartsWith(itemHidden.MenuPosition))
menuParts.Remove(item);
}

foreach (var menuPart in menuParts) {
if (menuPart != null) {
Expand Down
7 changes: 4 additions & 3 deletions src/Orchard.Web/Core/Navigation/Services/NavigationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public class NavigationManager : INavigationManager {

private IEnumerable<MenuItem> FinishMenu(ICollection<MenuItem> menuItems) {
foreach (var menuItem in menuItems) {
menuItem.Href = GetUrl(menuItem.Url, menuItem.RouteValues);
menuItem.Items = FinishMenu(menuItem.Items.ToArray());
}
menuItem.Href = GetUrl(menuItem.Url, menuItem.RouteValues);
menuItem.Items = FinishMenu(menuItem.Items.ToArray());
}

return menuItems;
}
Expand Down Expand Up @@ -276,6 +276,7 @@ public class NavigationManager : INavigationManager {
Position = SelectBestPositionValue(list.Select(x => x.Position)),
Permissions = list.SelectMany(x => x.Permissions).Distinct(),
Content = list.First().Content

};

return joined;
Expand Down