##// END OF EJS Templates
Child nodes should only be rendered if the user is actually authorized to see them (#15880)....
Jean-Philippe Lang -
r15011:8cbfeddeb011
parent child
Show More
@@ -1,454 +1,455
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module Redmine
19 19 module MenuManager
20 20 class MenuError < StandardError #:nodoc:
21 21 end
22 22
23 23 module MenuController
24 24 def self.included(base)
25 25 base.extend(ClassMethods)
26 26 end
27 27
28 28 module ClassMethods
29 29 @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}
30 30 mattr_accessor :menu_items
31 31
32 32 # Set the menu item name for a controller or specific actions
33 33 # Examples:
34 34 # * menu_item :tickets # => sets the menu name to :tickets for the whole controller
35 35 # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only
36 36 # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only
37 37 #
38 38 # The default menu item name for a controller is controller_name by default
39 39 # Eg. the default menu item name for ProjectsController is :projects
40 40 def menu_item(id, options = {})
41 41 if actions = options[:only]
42 42 actions = [] << actions unless actions.is_a?(Array)
43 43 actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}
44 44 else
45 45 menu_items[controller_name.to_sym][:default] = id
46 46 end
47 47 end
48 48 end
49 49
50 50 def menu_items
51 51 self.class.menu_items
52 52 end
53 53
54 54 # Returns the menu item name according to the current action
55 55 def current_menu_item
56 56 @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||
57 57 menu_items[controller_name.to_sym][:default]
58 58 end
59 59
60 60 # Redirects user to the menu item of the given project
61 61 # Returns false if user is not authorized
62 62 def redirect_to_project_menu_item(project, name)
63 63 item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}
64 64 if item && item.allowed?(User.current, project)
65 65 redirect_to({item.param => project}.merge(item.url))
66 66 return true
67 67 end
68 68 false
69 69 end
70 70 end
71 71
72 72 module MenuHelper
73 73 # Returns the current menu item name
74 74 def current_menu_item
75 75 controller.current_menu_item
76 76 end
77 77
78 78 # Renders the application main menu
79 79 def render_main_menu(project)
80 80 render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
81 81 end
82 82
83 83 def display_main_menu?(project)
84 84 menu_name = project && !project.new_record? ? :project_menu : :application_menu
85 85 Redmine::MenuManager.items(menu_name).children.present?
86 86 end
87 87
88 88 def render_menu(menu, project=nil)
89 89 links = []
90 90 menu_items_for(menu, project) do |node|
91 91 links << render_menu_node(node, project)
92 92 end
93 93 links.empty? ? nil : content_tag('ul', links.join.html_safe)
94 94 end
95 95
96 96 def render_menu_node(node, project=nil)
97 97 if node.children.present? || !node.child_menus.nil?
98 98 return render_menu_node_with_children(node, project)
99 99 else
100 100 caption, url, selected = extract_node_details(node, project)
101 101 return content_tag('li',
102 102 render_single_menu_node(node, caption, url, selected))
103 103 end
104 104 end
105 105
106 106 def render_menu_node_with_children(node, project=nil)
107 107 caption, url, selected = extract_node_details(node, project)
108 108
109 109 html = [].tap do |html|
110 110 html << '<li>'
111 111 # Parent
112 112 html << render_single_menu_node(node, caption, url, selected)
113 113
114 114 # Standard children
115 115 standard_children_list = "".html_safe.tap do |child_html|
116 116 node.children.each do |child|
117 child_html << render_menu_node(child, project)
117 child_html << render_menu_node(child, project) if allowed_node?(child, User.current, project)
118 118 end
119 119 end
120 120
121 121 html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?
122 122
123 123 # Unattached children
124 124 unattached_children_list = render_unattached_children_menu(node, project)
125 125 html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?
126 126
127 127 html << '</li>'
128 128 end
129 129 return html.join("\n").html_safe
130 130 end
131 131
132 132 # Returns a list of unattached children menu items
133 133 def render_unattached_children_menu(node, project)
134 134 return nil unless node.child_menus
135 135
136 136 "".html_safe.tap do |child_html|
137 137 unattached_children = node.child_menus.call(project)
138 138 # Tree nodes support #each so we need to do object detection
139 139 if unattached_children.is_a? Array
140 140 unattached_children.each do |child|
141 child_html << content_tag(:li, render_unattached_menu_item(child, project))
141 child_html << content_tag(:li, render_unattached_menu_item(child, project)) if allowed_node?(child, User.current, project)
142 142 end
143 143 else
144 144 raise MenuError, ":child_menus must be an array of MenuItems"
145 145 end
146 146 end
147 147 end
148 148
149 149 def render_single_menu_node(item, caption, url, selected)
150 150 link_to(h(caption), url, item.html_options(:selected => selected))
151 151 end
152 152
153 153 def render_unattached_menu_item(menu_item, project)
154 154 raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem
155 155
156 156 if menu_item.allowed?(User.current, project)
157 157 link_to(menu_item.caption, menu_item.url, menu_item.html_options)
158 158 end
159 159 end
160 160
161 161 def menu_items_for(menu, project=nil)
162 162 items = []
163 163 Redmine::MenuManager.items(menu).root.children.each do |node|
164 164 if node.allowed?(User.current, project)
165 165 if block_given?
166 166 yield node
167 167 else
168 168 items << node # TODO: not used?
169 169 end
170 170 end
171 171 end
172 172 return block_given? ? nil : items
173 173 end
174 174
175 175 def extract_node_details(node, project=nil)
176 176 item = node
177 177 url = case item.url
178 178 when Hash
179 179 project.nil? ? item.url : {item.param => project}.merge(item.url)
180 180 when Symbol
181 181 if project
182 182 send(item.url, project)
183 183 else
184 184 send(item.url)
185 185 end
186 186 else
187 187 item.url
188 188 end
189 189 caption = item.caption(project)
190 190 return [caption, url, (current_menu_item == item.name)]
191 191 end
192 192
193 193 # See MenuItem#allowed?
194 194 def allowed_node?(node, user, project)
195 raise MenuError, ":child_menus must be an array of MenuItems" unless node.is_a? MenuItem
195 196 node.allowed?(user, project)
196 197 end
197 198 end
198 199
199 200 class << self
200 201 def map(menu_name)
201 202 @items ||= {}
202 203 mapper = Mapper.new(menu_name.to_sym, @items)
203 204 if block_given?
204 205 yield mapper
205 206 else
206 207 mapper
207 208 end
208 209 end
209 210
210 211 def items(menu_name)
211 212 @items[menu_name.to_sym] || MenuNode.new(:root, {})
212 213 end
213 214 end
214 215
215 216 class Mapper
216 217 attr_reader :menu, :menu_items
217 218
218 219 def initialize(menu, items)
219 220 items[menu] ||= MenuNode.new(:root, {})
220 221 @menu = menu
221 222 @menu_items = items[menu]
222 223 end
223 224
224 225 # Adds an item at the end of the menu. Available options:
225 226 # * param: the parameter name that is used for the project id (default is :id)
226 227 # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true
227 228 # * caption that can be:
228 229 # * a localized string Symbol
229 230 # * a String
230 231 # * a Proc that can take the project as argument
231 232 # * before, after: specify where the menu item should be inserted (eg. :after => :activity)
232 233 # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)
233 234 # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item.
234 235 # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }
235 236 # * last: menu item will stay at the end (eg. :last => true)
236 237 # * html_options: a hash of html options that are passed to link_to
237 238 def push(name, url, options={})
238 239 options = options.dup
239 240
240 241 if options[:parent]
241 242 subtree = self.find(options[:parent])
242 243 if subtree
243 244 target_root = subtree
244 245 else
245 246 target_root = @menu_items.root
246 247 end
247 248
248 249 else
249 250 target_root = @menu_items.root
250 251 end
251 252
252 253 # menu item position
253 254 if first = options.delete(:first)
254 255 target_root.prepend(MenuItem.new(name, url, options))
255 256 elsif before = options.delete(:before)
256 257
257 258 if exists?(before)
258 259 target_root.add_at(MenuItem.new(name, url, options), position_of(before))
259 260 else
260 261 target_root.add(MenuItem.new(name, url, options))
261 262 end
262 263
263 264 elsif after = options.delete(:after)
264 265
265 266 if exists?(after)
266 267 target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)
267 268 else
268 269 target_root.add(MenuItem.new(name, url, options))
269 270 end
270 271
271 272 elsif options[:last] # don't delete, needs to be stored
272 273 target_root.add_last(MenuItem.new(name, url, options))
273 274 else
274 275 target_root.add(MenuItem.new(name, url, options))
275 276 end
276 277 end
277 278
278 279 # Removes a menu item
279 280 def delete(name)
280 281 if found = self.find(name)
281 282 @menu_items.remove!(found)
282 283 end
283 284 end
284 285
285 286 # Checks if a menu item exists
286 287 def exists?(name)
287 288 @menu_items.any? {|node| node.name == name}
288 289 end
289 290
290 291 def find(name)
291 292 @menu_items.find {|node| node.name == name}
292 293 end
293 294
294 295 def position_of(name)
295 296 @menu_items.each do |node|
296 297 if node.name == name
297 298 return node.position
298 299 end
299 300 end
300 301 end
301 302 end
302 303
303 304 class MenuNode
304 305 include Enumerable
305 306 attr_accessor :parent
306 307 attr_reader :last_items_count, :name
307 308
308 309 def initialize(name, content = nil)
309 310 @name = name
310 311 @children = []
311 312 @last_items_count = 0
312 313 end
313 314
314 315 def children
315 316 if block_given?
316 317 @children.each {|child| yield child}
317 318 else
318 319 @children
319 320 end
320 321 end
321 322
322 323 # Returns the number of descendants + 1
323 324 def size
324 325 @children.inject(1) {|sum, node| sum + node.size}
325 326 end
326 327
327 328 def each &block
328 329 yield self
329 330 children { |child| child.each(&block) }
330 331 end
331 332
332 333 # Adds a child at first position
333 334 def prepend(child)
334 335 add_at(child, 0)
335 336 end
336 337
337 338 # Adds a child at given position
338 339 def add_at(child, position)
339 340 raise "Child already added" if find {|node| node.name == child.name}
340 341
341 342 @children = @children.insert(position, child)
342 343 child.parent = self
343 344 child
344 345 end
345 346
346 347 # Adds a child as last child
347 348 def add_last(child)
348 349 add_at(child, -1)
349 350 @last_items_count += 1
350 351 child
351 352 end
352 353
353 354 # Adds a child
354 355 def add(child)
355 356 position = @children.size - @last_items_count
356 357 add_at(child, position)
357 358 end
358 359 alias :<< :add
359 360
360 361 # Removes a child
361 362 def remove!(child)
362 363 @children.delete(child)
363 364 @last_items_count -= +1 if child && child.last
364 365 child.parent = nil
365 366 child
366 367 end
367 368
368 369 # Returns the position for this node in it's parent
369 370 def position
370 371 self.parent.children.index(self)
371 372 end
372 373
373 374 # Returns the root for this node
374 375 def root
375 376 root = self
376 377 root = root.parent while root.parent
377 378 root
378 379 end
379 380 end
380 381
381 382 class MenuItem < MenuNode
382 383 include Redmine::I18n
383 384 attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last, :permission
384 385
385 386 def initialize(name, url, options={})
386 387 raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
387 388 raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash)
388 389 raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym
389 390 raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call)
390 391 @name = name
391 392 @url = url
392 393 @condition = options[:if]
393 394 @permission = options[:permission]
394 395 @permission ||= false if options.key?(:permission)
395 396 @param = options[:param] || :id
396 397 @caption = options[:caption]
397 398 @html_options = options[:html] || {}
398 399 # Adds a unique class to each menu item based on its name
399 400 @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
400 401 @parent = options[:parent]
401 402 @child_menus = options[:children]
402 403 @last = options[:last] || false
403 404 super @name.to_sym
404 405 end
405 406
406 407 def caption(project=nil)
407 408 if @caption.is_a?(Proc)
408 409 c = @caption.call(project).to_s
409 410 c = @name.to_s.humanize if c.blank?
410 411 c
411 412 else
412 413 if @caption.nil?
413 414 l_or_humanize(name, :prefix => 'label_')
414 415 else
415 416 @caption.is_a?(Symbol) ? l(@caption) : @caption
416 417 end
417 418 end
418 419 end
419 420
420 421 def html_options(options={})
421 422 if options[:selected]
422 423 o = @html_options.dup
423 424 o[:class] += ' selected'
424 425 o
425 426 else
426 427 @html_options
427 428 end
428 429 end
429 430
430 431 # Checks if a user is allowed to access the menu item by:
431 432 #
432 433 # * Checking the permission or the url target (project only)
433 434 # * Checking the conditions of the item
434 435 def allowed?(user, project)
435 436 if user && project
436 437 if permission
437 438 unless user.allowed_to?(permission, project)
438 439 return false
439 440 end
440 441 elsif permission.nil? && url.is_a?(Hash)
441 442 unless user.allowed_to?(url, project)
442 443 return false
443 444 end
444 445 end
445 446 end
446 447 if condition && !condition.call(project)
447 448 # Condition that doesn't pass
448 449 return false
449 450 end
450 451 return true
451 452 end
452 453 end
453 454 end
454 455 end
@@ -1,260 +1,306
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../../../test_helper', __FILE__)
19 19
20 20 class Redmine::MenuManager::MenuHelperTest < ActionView::TestCase
21 21
22 22 include Redmine::MenuManager::MenuHelper
23 23 include ERB::Util
24 24 fixtures :users, :members, :projects, :enabled_modules, :roles, :member_roles
25 25
26 26 def setup
27 27 setup_with_controller
28 28 # Stub the current menu item in the controller
29 29 def current_menu_item
30 30 :index
31 31 end
32 32 end
33 33
34 34 def test_render_single_menu_node
35 35 node = Redmine::MenuManager::MenuItem.new(:testing, '/test', { })
36 36 @output_buffer = render_single_menu_node(node, 'This is a test', node.url, false)
37 37
38 38 assert_select("a.testing", "This is a test")
39 39 end
40 40
41 41 def test_render_menu_node
42 42 single_node = Redmine::MenuManager::MenuItem.new(:single_node, '/test', { })
43 43 @output_buffer = render_menu_node(single_node, nil)
44 44
45 45 assert_select("li") do
46 46 assert_select("a.single-node", "Single node")
47 47 end
48 48 end
49 49
50 50 def test_render_menu_node_with_symbol_as_url
51 51 node = Redmine::MenuManager::MenuItem.new(:testing, :issues_path)
52 52 @output_buffer = render_menu_node(node, nil)
53 53
54 54 assert_select 'a[href="/issues"]', "Testing"
55 55 end
56 56
57 57 def test_render_menu_node_with_symbol_as_url_and_project
58 58 node = Redmine::MenuManager::MenuItem.new(:testing, :project_issues_path)
59 59 @output_buffer = render_menu_node(node, Project.find(1))
60 60
61 61 assert_select 'a[href="/projects/ecookbook/issues"]', "Testing"
62 62 end
63 63
64 64 def test_render_menu_node_with_nested_items
65 65 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node, '/test', { })
66 66 parent_node << Redmine::MenuManager::MenuItem.new(:child_one_node, '/test', { })
67 67 parent_node << Redmine::MenuManager::MenuItem.new(:child_two_node, '/test', { })
68 68 parent_node <<
69 69 Redmine::MenuManager::MenuItem.new(:child_three_node, '/test', { }) <<
70 70 Redmine::MenuManager::MenuItem.new(:child_three_inner_node, '/test', { })
71 71
72 72 @output_buffer = render_menu_node(parent_node, nil)
73 73
74 74 assert_select("li") do
75 75 assert_select("a.parent-node", "Parent node")
76 76 assert_select("ul") do
77 77 assert_select("li a.child-one-node", "Child one node")
78 78 assert_select("li a.child-two-node", "Child two node")
79 79 assert_select("li") do
80 80 assert_select("a.child-three-node", "Child three node")
81 81 assert_select("ul") do
82 82 assert_select("li a.child-three-inner-node", "Child three inner node")
83 83 end
84 84 end
85 85 end
86 86 end
87 87
88 88 end
89 89
90 90 def test_render_menu_node_with_children
91 91 User.current = User.find(2)
92 92
93 93 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
94 94 '/test',
95 95 {
96 96 :children => Proc.new {|p|
97 97 children = []
98 98 3.times do |time|
99 99 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}",
100 100 {:controller => 'issues', :action => 'index'},
101 101 {})
102 102 end
103 103 children
104 104 }
105 105 })
106 106 @output_buffer = render_menu_node(parent_node, Project.find(1))
107 107
108 108 assert_select("li") do
109 109 assert_select("a.parent-node", "Parent node")
110 110 assert_select("ul") do
111 111 assert_select("li a.test-child-0", "Test child 0")
112 112 assert_select("li a.test-child-1", "Test child 1")
113 113 assert_select("li a.test-child-2", "Test child 2")
114 114 end
115 115 end
116 116 end
117 117
118 118 def test_render_menu_node_with_nested_items_and_children
119 119 User.current = User.find(2)
120 120
121 121 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
122 '/test',
122 {:controller => 'issues', :action => 'index'},
123 123 {
124 124 :children => Proc.new {|p|
125 125 children = []
126 126 3.times do |time|
127 127 children << Redmine::MenuManager::MenuItem.new("test_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
128 128 end
129 129 children
130 130 }
131 131 })
132 132
133 133 parent_node << Redmine::MenuManager::MenuItem.new(:child_node,
134 '/test',
134 {:controller => 'issues', :action => 'index'},
135 135 {
136 136 :children => Proc.new {|p|
137 137 children = []
138 138 6.times do |time|
139 139 children << Redmine::MenuManager::MenuItem.new("test_dynamic_child_#{time}", {:controller => 'issues', :action => 'index'}, {})
140 140 end
141 141 children
142 142 }
143 143 })
144 144
145 145 @output_buffer = render_menu_node(parent_node, Project.find(1))
146 146
147 147 assert_select("li") do
148 148 assert_select("a.parent-node", "Parent node")
149 149 assert_select("ul") do
150 150 assert_select("li a.child-node", "Child node")
151 151 assert_select("ul") do
152 152 assert_select("li a.test-dynamic-child-0", "Test dynamic child 0")
153 153 assert_select("li a.test-dynamic-child-1", "Test dynamic child 1")
154 154 assert_select("li a.test-dynamic-child-2", "Test dynamic child 2")
155 155 assert_select("li a.test-dynamic-child-3", "Test dynamic child 3")
156 156 assert_select("li a.test-dynamic-child-4", "Test dynamic child 4")
157 157 assert_select("li a.test-dynamic-child-5", "Test dynamic child 5")
158 158 end
159 159 assert_select("li a.test-child-0", "Test child 0")
160 160 assert_select("li a.test-child-1", "Test child 1")
161 161 assert_select("li a.test-child-2", "Test child 2")
162 162 end
163 163 end
164 164 end
165 165
166 def test_render_menu_node_with_allowed_and_unallowed_unattached_children
167 User.current = User.find(2)
168
169 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
170 {:controller => 'issues', :action => 'index'},
171 {
172 :children => Proc.new {|p|
173 [
174 Redmine::MenuManager::MenuItem.new("test_child_allowed", {:controller => 'issues', :action => 'index'}, {}),
175 Redmine::MenuManager::MenuItem.new("test_child_unallowed", {:controller => 'issues', :action => 'unallowed'}, {}),
176 ]
177 }
178 })
179
180 @output_buffer = render_menu_node(parent_node, Project.find(1))
181
182 assert_select("li") do
183 assert_select("a.parent-node", "Parent node")
184 assert_select("ul.menu-children.unattached") do
185 assert_select("li a.test-child-allowed", "Test child allowed")
186 assert_select("li a.test-child-unallowed", false)
187 end
188 end
189 end
190
191 def test_render_menu_node_with_allowed_and_unallowed_standard_children
192 User.current = User.find(6)
193
194 Redmine::MenuManager.map :some_menu do |menu|
195 menu.push(:parent_node, {:controller => 'issues', :action => 'index'}, { })
196 menu.push(:test_child_allowed, {:controller => 'issues', :action => 'index'}, {:parent => :parent_node})
197 menu.push(:test_child_unallowed, {:controller => 'issues', :action => 'new'}, {:parent => :parent_node})
198 end
199
200 @output_buffer = render_menu(:some_menu, Project.find(1))
201
202 assert_select("li") do
203 assert_select("a.parent-node", "Parent node")
204 assert_select("ul.menu-children.unattached", false)
205 assert_select("ul.menu-children") do
206 assert_select("li a.test-child-allowed", "Test child allowed")
207 assert_select("li a.test-child-unallowed", false)
208 end
209 end
210 end
211
166 212 def test_render_menu_node_with_children_without_an_array
167 213 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
168 214 '/test',
169 215 {
170 216 :children => Proc.new {|p| Redmine::MenuManager::MenuItem.new("test_child", "/testing", {})}
171 217 })
172 218
173 219 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
174 220 @output_buffer = render_menu_node(parent_node, Project.find(1))
175 221 end
176 222 end
177 223
178 224 def test_render_menu_node_with_incorrect_children
179 225 parent_node = Redmine::MenuManager::MenuItem.new(:parent_node,
180 226 '/test',
181 227 {
182 228 :children => Proc.new {|p| ["a string"] }
183 229 })
184 230
185 231 assert_raises Redmine::MenuManager::MenuError, ":children must be an array of MenuItems" do
186 232 @output_buffer = render_menu_node(parent_node, Project.find(1))
187 233 end
188 234
189 235 end
190 236
191 237 def test_menu_items_for_should_yield_all_items_if_passed_a_block
192 238 menu_name = :test_menu_items_for_should_yield_all_items_if_passed_a_block
193 239 Redmine::MenuManager.map menu_name do |menu|
194 240 menu.push(:a_menu, '/', { })
195 241 menu.push(:a_menu_2, '/', { })
196 242 menu.push(:a_menu_3, '/', { })
197 243 end
198 244
199 245 items_yielded = []
200 246 menu_items_for(menu_name) do |item|
201 247 items_yielded << item
202 248 end
203 249
204 250 assert_equal 3, items_yielded.size
205 251 end
206 252
207 253 def test_menu_items_for_should_return_all_items
208 254 menu_name = :test_menu_items_for_should_return_all_items
209 255 Redmine::MenuManager.map menu_name do |menu|
210 256 menu.push(:a_menu, '/', { })
211 257 menu.push(:a_menu_2, '/', { })
212 258 menu.push(:a_menu_3, '/', { })
213 259 end
214 260
215 261 items = menu_items_for(menu_name)
216 262 assert_equal 3, items.size
217 263 end
218 264
219 265 def test_menu_items_for_should_skip_unallowed_items_on_a_project
220 266 menu_name = :test_menu_items_for_should_skip_unallowed_items_on_a_project
221 267 Redmine::MenuManager.map menu_name do |menu|
222 268 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
223 269 menu.push(:a_menu_2, {:controller => 'issues', :action => 'index' }, { })
224 270 menu.push(:unallowed, {:controller => 'issues', :action => 'unallowed' }, { })
225 271 end
226 272
227 273 User.current = User.find(2)
228 274
229 275 items = menu_items_for(menu_name, Project.find(1))
230 276 assert_equal 2, items.size
231 277 end
232 278
233 279 def test_menu_items_for_should_skip_items_that_fail_the_permission
234 280 menu_name = :test_menu_items_for_should_skip_items_that_fail_the_permission
235 281 Redmine::MenuManager.map menu_name do |menu|
236 282 menu.push(:a_menu, :project_issues_path)
237 283 menu.push(:unallowed, :project_issues_path, :permission => :unallowed)
238 284 end
239 285
240 286 User.current = User.find(2)
241 287
242 288 items = menu_items_for(menu_name, Project.find(1))
243 289 assert_equal 1, items.size
244 290 end
245 291
246 292 def test_menu_items_for_should_skip_items_that_fail_the_conditions
247 293 menu_name = :test_menu_items_for_should_skip_items_that_fail_the_conditions
248 294 Redmine::MenuManager.map menu_name do |menu|
249 295 menu.push(:a_menu, {:controller => 'issues', :action => 'index' }, { })
250 296 menu.push(:unallowed,
251 297 {:controller => 'issues', :action => 'index' },
252 298 { :if => Proc.new { false }})
253 299 end
254 300
255 301 User.current = User.find(2)
256 302
257 303 items = menu_items_for(menu_name, Project.find(1))
258 304 assert_equal 1, items.size
259 305 end
260 306 end
General Comments 0
You need to be logged in to leave comments. Login now