From b4270d1001fc675738acffbd7fc936970512f80d Mon Sep 17 00:00:00 2001 From: Jan Schulz-Hofen Date: Wed, 5 Feb 2014 12:45:37 +0700 Subject: [PATCH 1/6] introduce virtual MenuNodes which are characterized by having a blank url. they will only be rendered if the user is authorized to see at least one of its children. they render as links which do nothing when clicked. --- lib/redmine/menu_manager.rb | 19 ++++++++++-- .../lib/redmine/menu_manager/menu_helper_test.rb | 35 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/redmine/menu_manager.rb b/lib/redmine/menu_manager.rb index fa77770..0d2d19a 100644 --- a/lib/redmine/menu_manager.rb +++ b/lib/redmine/menu_manager.rb @@ -147,7 +147,15 @@ module Redmine end def render_single_menu_node(item, caption, url, selected) - link_to(h(caption), url, item.html_options(:selected => selected)) + options = item.html_options(:selected => selected) + + # virtual nodes are only there for their children to be displayed in the menu + # and should not do anything on click, except if otherwise defined elsewhere + if url.blank? + url = '#' + options.reverse_merge!(:onclick => 'return false;') + end + link_to(h(caption), url, options) end def render_unattached_menu_item(menu_item, project) @@ -433,7 +441,14 @@ module Redmine # * Checking the permission or the url target (project only) # * Checking the conditions of the item def allowed?(user, project) - if user && project + if url.blank? + # this is a virtual node that is only there for its children to be diplayed in the menu + # it is considered an allowed node if at least one of the children is allowed + all_children = children + all_children += child_menus.call(project) if child_menus + return true if all_children.detect{|child| child.allowed?(user, project) } + return false + elsif user && project if permission unless user.allowed_to?(permission, project) return false diff --git a/test/unit/lib/redmine/menu_manager/menu_helper_test.rb b/test/unit/lib/redmine/menu_manager/menu_helper_test.rb index 404ec64..9a3aa0a 100644 --- a/test/unit/lib/redmine/menu_manager/menu_helper_test.rb +++ b/test/unit/lib/redmine/menu_manager/menu_helper_test.rb @@ -209,6 +209,41 @@ class Redmine::MenuManager::MenuHelperTest < ActionView::TestCase end end + def test_render_empty_virtual_menu_node_with_children + + # only empty item with no click target + Redmine::MenuManager.map :menu1 do |menu| + menu.push(:parent_node, nil, { }) + end + + # parent with unallowed unattached child + Redmine::MenuManager.map :menu2 do |menu| + menu.push(:parent_node, nil, {:children => Proc.new {|p| + [Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'new'}, {})] + } }) + end + + # parent with unallowed standard child + Redmine::MenuManager.map :menu3 do |menu| + menu.push(:parent_node, nil, {}) + menu.push(:test_child_unallowed, {:controller =>'issues', :action => 'new'}, {:parent => :parent_node}) + end + + # should not be displayed to anonymous + User.current = User.find(6) + assert_nil render_menu(:menu1, Project.find(1)) + assert_nil render_menu(:menu2, Project.find(1)) + assert_nil render_menu(:menu3, Project.find(1)) + + # should be displayed to an admin + User.current = User.find(1) + @output_buffer = render_menu(:menu2, Project.find(1)) + assert_select("ul li a.parent-node", "Parent node") + @output_buffer = render_menu(:menu3, Project.find(1)) + assert_select("ul li a.parent-node", "Parent node") + + end + def test_render_menu_node_with_children_without_an_array parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', -- 2.7.2