Empty admin categories are not hidden

icouto - August 18, 2008 - 11:42
Project:Drupal
Version:7.x-dev
Component:menu system
Category:bug report
Priority:normal
Assigned:Unassigned
Status:closed
Issue tags:Needs Documentation
Description

Under Drupal 6(.4), even if a role has *no* User-Management related permissions, the "User Management" menu does not hide - it still shows, with no items under it. Selecting the menu takes the user to a page that simply states: "You do not have any administrative items."

It seems to me, that the menu simply should not be present.

To reproduce, using a brand-new D6.4 installation:

1) login as the site's superuser, and create a new role - name it anything you wish
2) In the 'permissions' page for the new role, make sure the role has *no* user management permissions - under "user module", deselect everything.
3) create a new user for the site, and give this user the newly created role
4) log out as the superuser, and login as the new user, with the new role
5) notice that under 'Administer', you still have "User Management" - clicking it will take you to that silly page that states that you have no administrative items...

This is a *very* annoying bug. I do *not* wish the "User Management" menu to be displayed for certain roles - ie., 'site editors', whose function is simply to add and edit content to the site.

#1

icouto - August 19, 2008 - 06:27

The same problem is also reproducible for the "Site Building" menu - ie., even if the role has no permissions for any of the menu items in the menu, the menu itself is still displayed. I suspect the same thing might happen also for the "Site Configuration" menu.

This *is* a serious problem to me, as one of the main tasks I have when setting up a Drupal site is to 'dumb down' the admin interface for newbie users. Not being able to easily hide these menus means that the interface ends up being overly complicated for low-level admin users - like site editors, who have no business managing users, or playing around with the site configuration.

Currently, the only way to overcome this bug is to split the Administer menu into several menus (one for each role needed), and use the BLOCK permissions for each menu block individually. In my case, for instance, I ended up having to split the menu into "RegisteredUser", "SiteEditor" and "SiteAdmin" menus. This is not a proper solution, it is a time-consuming, inelegant hack. I end up with 3 or 4 separate menus, containing totally related functions that had to be split in order for me to be able to control role access to them - when they really should be under just a single menu.

I do not need several different menus. I need just ONE menu, that properly restricts its items' visibility according to the user's permissions.

I hope this will be fixed for D7.

#2

Damien Tournoud - August 19, 2008 - 23:27
Title:Overly Persistent "User Management" Menu» Empty admin categories should be hidden
Version:6.x-dev» 7.x-dev
Component:menu system» system.module
Status:active» needs review

That issue has been identified several months ago. Here is a first patch for it.

AttachmentSize
296693-empty-admin-categories.patch 5.25 KB
Testbed results
296693-empty-admin-categories.patchfailedFailed: Failed to apply patch. Detailed results

#3

webchick - August 20, 2008 - 16:22
Status:needs review» needs work

Confirmed this problem. Would be nice to back-port fix to 6.x as well.

Steps to reproduce:
- Create a role called "editor" and an "editor" user assigned to that role.
- Give the role both "administer nodes" and "access administration pages" permissions.
- Log in as "editor" and go to "Administration"
You'll see entries for Site building, etc. in the navigation menu even though those result in "Access denied" when you try to go there. See attached screenshot.

Let's get tests with this patch though to make sure this bug doesn't recur.

AttachmentSize
empty-admin-categories-no-patch.png 70.59 KB

#4

boombatower - August 20, 2008 - 18:55

The code in #2 uses system_admin_menu_block() which does allot of extra stuff then is necessary to determine if there are children. Plus _system_settings_access doesn't seem like the right name for the access callback for two reasons.
1) It could be used by contrib, no need for private declaration (_).
2) It relates to other items besides settings.

In my attempt at this in #263616: Move SimpleTest out of "Site building" I used the following code:

<?php
function system_admin_menu_block_page_access($path, $string) {
  if (
user_access($string)) {
   
$count = db_result(db_query("SELECT COUNT(mlid)
                                 FROM {menu_links}
                                 WHERE plid = (
                                   SELECT mlid
                                   FROM {menu_links}
                                   WHERE link_path
                                   LIKE '%s'
                                 )"
, $path));
    return (
$count > 0);
  }
  return
FALSE;
}
?>

Which alleviates the call to the other function.

Should think about the name of the function. The reasoning behind my choice is that the items that only display a list of children use system_admin_menu_block_page so it would only seem nature that system_admin_menu_block_page_access would be used for them.

#5

Damien Tournoud - August 20, 2008 - 19:05

@boomatower: Ok for the name change, it makes sense and I don't really care :)

The objective of using system_admin_menu_block() was to limit code duplication and database queries as most as possible. Your solution was not enough, because we also need to check for access of each menu item, not just count them.

I turned that issue around over and over, and came to the conclusion there is no better way.

#6

Damien Tournoud - August 20, 2008 - 19:06

I forgot to add: "... but of course, I only want to be proven wrong!"

#7

boombatower - August 20, 2008 - 22:52
Assigned to:Anonymous» boombatower

Working on writing the test, and a few cleanup items along with it.

#8

icouto - August 20, 2008 - 23:29

Thank you, everyone, for your superhumanly quick response to this!

I was wondering, if we are going to see a back-port of the fix in D6, as mentioned by webchick.

#9

boombatower - August 20, 2008 - 23:48
Status:needs work» needs review

Adds test and changes access callback name per #4 and #5.

@icouto: Depends on what this is considered. If this is considered a bug/or necessary feature then it most likely will be. It would be useful as SimpleTest 6.x-2.x would use this and I'm sure there are others, not to mention default use-cases as per #3.

The test needs assertLink and assertNoLink: #297894: Add assertLink and assertNoLink to SimpleTest
which requires: #297869: Add xpath method to Simpletest and refactor existing tests

Will need those to get in first, but we can still review this patch. (although you will need to apply those.)

After patches applies test passes.

AttachmentSize
296693-empty-admin-categories.patch 7.19 KB
Testbed results
296693-empty-admin-categories.patchfailedFailed: Failed to apply patch. Detailed results

#10

boombatower - August 21, 2008 - 00:14

After applying the above patches and then applying this one tests pass.

#11

boombatower - August 21, 2008 - 00:34

Ran entire test suite with all passes.

#12

boombatower - August 23, 2008 - 20:49

Still applies after dbtng.

#13

lilou - August 24, 2008 - 00:20
Status:needs review» needs work

There is a bug with the last patch :

1. Give anonymous user these permissions :

access administration pages and administer blocks or access site reports.

2. Clear cache

3. Logout

4. Go to admin page >> Access denied, and no menu link

5. Refresh >> Notice error :

warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'system_admin_menu_block_page_access' was given in D:\Serveur\www\drupal\7.x\includes\menu.inc on line 502.

warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'system_admin_menu_block_page_access' was given in D:\Serveur\www\drupal\7.x\includes\menu.inc on line 502.

#14

boombatower - August 24, 2008 - 01:21

Hmmmm...two interesting things:

  • The notice only comes up once...at least for me.
  • Adding debug code it becomes clear that user_access() returns TRUE, but the $content is empty.

It would seem the issue is in the existing code not the new code, but yet it works without the new code....

When I run the site as anonymous I get:

error  PHP Fatal error: require_once(): Failed opening required './includes/database/mysql/query.inc' (include_path='.:/usr/share/php5:/usr/share/php5/PEAR') in .../drupal-7/includes/bootstrap.inc on line 1399, referer: http://drupal-7.dev.loc/

#15

Damien Tournoud - August 24, 2008 - 14:13
Status:needs work» needs review

There are three bugs here:

* Drupal don't use absolute paths for loading include files, and the current path can change, especially during the execution of shutdown functions. This is solved in #259623: Broken autoloader: convert includes/requires to use absolute paths. Please try that patch.
* Access control on /admin don't work properly, probably because system_admin_menu_block_page_access() recursively calls itself. For now, I disabled that access control on /admin.
* Hide descriptions/Show descriptions toggles didn't work for anonymous users (it was relying on a $user parameter). I changed this to use session for anonymous users.

AttachmentSize
296693-empty-admin-categories.patch 6.69 KB
Testbed results
296693-empty-admin-categories.patchfailedFailed: Failed to apply patch. Detailed results

#16

keith.smith - August 24, 2008 - 16:50

Not to be overly picky on code comments, but:

+   * Ensure that menu items that without "visible" children are hidden.

An extra "that" or something?

+ *   The path of the menu item to ensure has children.

Something's not quite right there.

I see this is another good use of compact mode, which I wholeheartedly approve. We don't use setting enough.

These are minor, so I'll leave at CNR and you can take care of them during the next substantive re-roll.

#17

Anonymous (not verified) - November 11, 2008 - 14:00
Status:needs review» needs work

The last submitted patch failed testing.

#18

sun - December 29, 2008 - 18:52

Subscribing and marking for later review. Administration menu module users are suffering from this.

#19

deviantintegral - December 29, 2008 - 21:41

Here is an updated patch which applies against HEAD and fixes the comments in #16. It's working as expected for me.

AttachmentSize
296693-empty-admin-categories.patch 6.66 KB
Testbed results
296693-empty-admin-categories.patchfailedFailed: Failed to install HEAD. Detailed results

#20

sun - December 31, 2008 - 00:59
Assigned to:boombatower» Anonymous
Status:needs work» needs review

- Renamed menu item access callback to system_admin_menu_block_access(), since the additional "page" suggested that it would be used for determining access to a page, but we are just checking admin block/category access here.

- Optimized system_admin_menu_block_access() to check for the user permissions first.

- Removed all changes related to compact mode, as those are unrelated to this issue. (please create a new issue, since the changes make sense)

- Renamed test case.

Also ran tests, tested manually with a test user (and having admin menu module installed) and everything seems to working properly.

AttachmentSize
drupal.hide-empty-admin-categories.patch 6.03 KB
Testbed results
drupal.hide-empty-admin-categories.patchfailedFailed: Failed to install HEAD. Detailed results

#21

sun - December 31, 2008 - 00:59
Title:Empty admin categories should be hidden» Empty admin categories are not hidden

This is a annoying bug - better title.

#22

Damien Tournoud - December 31, 2008 - 01:09
Status:needs review» needs work

Changes in #20 make sense, but this is an old patch, and its test doesn't comply at all with our (relatively new) Test Writers Guidelines.

<?php
  
}
}

+class
AdminMenuBlockTestCase extends DrupalWebTestCase {
?>

^^ Missing PHPDoc above the class.

<?php
/**
+   * Implementation of getInfo().
+   */
+  function getInfo() {
?>

^^ We don't PHPDoc overriden functions anymore.

<?php
+    return array(
+     
'name' => t('Admin menu categories'),
+     
'description' => t('Confirm that administrative categories, which do not contain any visible child items, are not displayed.'),
+     
'group' => t('System'),
+    );
+  }
?>

<?php
+
/**
+   * Ensure that administrative menu items without visible children are hidden.
+   */
+  public function testEmptyHide() {
?>

^^ The PHPDoc description should probably better start with test*...

testEmptyHide() is a badly choosen function name.

As an end note: it's quite fun to shoot down one of your own old patches :)

#23

sun - December 31, 2008 - 01:40
Status:needs work» needs review

After a BIG support session with Damien in IRC, this should (hopefully) be properly. :) (Thanks again!)

AttachmentSize
drupal.hide-empty-admin-menus.patch 6.01 KB
Testbed results
drupal.hide-empty-admin-menus.patchfailedFailed: 8502 passes, 1 fail, 0 exceptions Detailed results

#24

sun - December 31, 2008 - 01:53

FYI: Damien moved the compact mode fixes to #352734: "Compact mode" switch doesn't work for anonymous users...

#25

System Message - January 8, 2009 - 00:50
Status:needs review» needs work

The last submitted patch failed testing.

#26

Damien Tournoud - January 8, 2009 - 15:22
Status:needs work» needs review

#27

System Message - January 9, 2009 - 17:20
Status:needs review» needs work

The last submitted patch failed testing.

#28

Xano - January 23, 2009 - 15:35

While working at #362834: Move statistics out of the administration pages and add permissions I noticed that MENU_ITEM_GROUPING has not been added to the new menu system in D7. As a result, we now have several functions that do pretty much the same. node_add_page() and system_admin_menu_block_page(). I think node_add_page() is a good candidate for a new MENU_ITEM_GROUPING. It needs some changes, but then it will do fine (See the patch in #362834).

However, that patch is not complete yet, since it displays a MENU_ITEM_GROUPING parent item even if there are no child items or if the user has no permission to access any of its child items. This is the point where chx told me to check out this issue.

  1. I believe the names system_admin_menu_block() and system_admin_menu_block_page() are improper. They don't describe what the functions do in a short and simple fashion, nor do they make the functionality appear available to non-admin pages, which should be.
  2. I suggest I suggest putting MENU_ITEM_GROUPING back in and let menu.inc automatically set menu_item_grouping() (as seen below) as the page callback. Menu.inc should also set special access callback that returns FALSE if there are no children or if the user has no permission to access them.
  3. The access callback as described in #4 only checks if there are no child items, but it should also check if the user has permission to access those children. This could perhaps be done the easiest by creating a user_access_multiple() (issue), so multiple permissions can be checked at once.
  4. <?php
    /**
    * List a menu item's children.
    *
    * @return string
    */
    function menu_item_grouping() {
     
    $item = menu_get_item();
     
    $items = system_admin_menu_block($item);
     
    // Bypass the listing if only one child is available.
     
    if (count($items) == 1) {
       
    $item = array_shift($items);
       
    drupal_goto($item['href']);
      }
      return
    theme('menu_item_grouping', $items);
    }

    /**
    * Theme a list of menu items.
    *
    * @param $items
    *   The items as returned from system_admin_menu_block().
    *
    * @return string
    */
    function theme_menu_item_grouping($items) {
     
    $output = '';

      if (
    $items) {
       
    $output = '<dl class="menu-item-grouping">';
        foreach (
    $items as $item) {
         
    $output .= '<dt>' . l($item['title'], $item['href'], $item['localized_options']) . '</dt>';
         
    $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>';
        }
       
    $output .= '</dl>';
      }
      return
    $output;
    }
    ?>

#29

Xano - January 25, 2009 - 12:00
Title:Empty admin categories are not hidden» MENU_ITEM_GROUPING
Component:system.module» menu system
Assigned to:Anonymous» Xano
Status:needs work» needs review

The attached patch reintroduces MENU_ITEM_GROUPING as a menu item type. Such menu items automatically get a page callback that lists all the item's children, or redirects the user if there is only one child.

  1. To do: Hide the menu item if there are no children. I must say I'm not sure if this is the way to go, since it could cause some links not to be visible anywhere, although they have been enabled at admin/build/menu.
  2. To do: Check if the user has permission to access any children, otherwise hide the item.
  3. Custom access callbacks should be used in parallel with the access callbacks from points 1 and 2.

See this patch in action at /node/add. See anything different? No? Exactly!

By the way: node_add_page() and similar obsolete functions have not yet been removed to keep this initial patch simple.

AttachmentSize
menu_item_grouping_00.patch 3.87 KB
Testbed results
menu_item_grouping_00.patchfailedFailed: Failed to apply patch. Detailed results

#30

Xano - January 25, 2009 - 13:45

The attached patch also performs access control and should hide the item if a user has no access to child items. All issues pointed out in #29 are dealt with. I haven't yet tested the patch thoroughly, but it seems to work. Will do more testing as soon as I'm done with my other work here.

To do: display a message if there are no children to list.

The code responsible for the access check:

<?php
/**
* Determine if a user should have access to a menu item.
*
* Users should only have access if all of the following cases are true:
* - The user has access to at least one of this item's children.
* - The custom access callback (if any) returns TRUE.
*
* @param $path string
*   The path of the menu item to check access to.
* @param $callback string
*   A custom access callback to check as well.
* @param $arguments array
*   Arguments to pass on to the access callback.
*
* @return boolean
*/
function menu_item_grouping_access($path, $callback, $arguments) {
  if (
is_string($callback)) {
   
$custom_access = call_user_func_array($callback, $arguments);
  }

 
$item = array('path' => $path);
 
$items = system_admin_menu_block($item);
  foreach (
$items as $child) {
   
_menu_check_access($child, array());
    if (
$child['access']) {
      if (
$custom_access) {
        return
TRUE;
      }
      else {
        return
FALSE;
      }
    }
  }

  return
FALSE;
}
?>

AttachmentSize
menu_item_grouping_01.patch 5.16 KB
Testbed results
menu_item_grouping_01.patchfailedFailed: Failed to apply patch. Detailed results

#31

chx - January 25, 2009 - 15:50

Benchmarks?

#32

Xano - January 25, 2009 - 16:22
Title:MENU_ITEM_GROUPING» Empty admin categories are not hidden
Assigned to:Xano» Anonymous
Status:needs review» active

I have split the patch in two. After #363951: Reintroduction of MENU_ITEM_GROUPING gets submitted I'll post a new patch taking care of access control here. This will make benchmarking easier.

#33

stella - February 11, 2009 - 17:19
Title:Empty admin categories are not hidden » Empty admin categories are not hidden

subscribe

#34

mairav - March 4, 2009 - 20:07

Suscribe using Drupal 6.10.
Will drupal fix this to 6 version or will it be a solution for Drupal 7?

#35

mrfelton - March 12, 2009 - 08:53

Subscribing too, if a Drupal 6 backport is on the cards.

#36

nwe_44 - May 12, 2009 - 16:18

Subscribing.

#37

jusspitti - May 26, 2009 - 11:12

Subscribing and looking forward for d6 patch

#38

stella - May 26, 2009 - 11:24

Since #363951: Reintroduction of MENU_ITEM_GROUPING won't be committed (marked as won't fix), does this mean we're back to the patch in #20 above?

#39

boombatower - May 26, 2009 - 15:35
Status:active» needs review

Rework of #23 (no longer applied and outdated).

  • Make use of drupal_static().
  • Implement callback for admin/development.
  • Updated test for admin/development.
AttachmentSize
296693-menu-hide.patch 6.39 KB
Testbed results
296693-menu-hide.patchfailedFailed: Failed to apply patch. Detailed results

#40

stella - May 26, 2009 - 17:06

Patch looks good and works quite well. However there's still one edge case that isn't covered - if the user has the 'access administration pages' permission, but doesn't have access to _any_ of the sub menus, and if the help module is not enabled, then the 'Administer' menu item still appears in the navigation block and the message "You do not have any administrative items." appears when clicked.

It's an edge case (why would anyone give that permission to a user without giving them access to at least one sub-menu?!) and the message displayed is useful, but shouldn't that menu item not appear at all?

#41

stella - May 26, 2009 - 17:11
Status:needs review» needs work

Actually this also change also needs to be implemented for the new top level admin menu admin/international in locale.module

#42

boombatower - May 26, 2009 - 18:31
Status:needs work» needs review

I am not sure that is an issue since technically there is a menu item under "Administration". When help module is disabled the Administration menu item still displays. I attempted to add the check the the root "admin" item, but it causes an issue, possibly due to excessive looping.

Not sure we want to deal with that issue or perhaps save for follup patch. Either way this patch contains admin/international alteration.

AttachmentSize
296693-menu-hide.patch 7.14 KB
Testbed results
296693-menu-hide.patchfailedFailed: Failed to apply patch. Detailed results

#43

stella - May 26, 2009 - 18:43

I think it's good to go as is, just to summarise what this patch does:

  • For each of the top level admin menu items (admin/build, admin/user, etc), it changes the access callback to be a new function system_admin_menu_block_page and gives it the params: path (e.g. 'admin/build') and the access permission.
  • The function first checks that the user has the appropriate access, and if not returns FALSE.
  • then checks if the user has access to any of the sub-menus, and if not it returns FALSE, which prevents the user from seeing the menu item

#44

sun - May 26, 2009 - 18:52
Status:needs review» reviewed & tested by the community

Yes. 'admin' & 'access administration pages' we need to tackle elsewhere.

#45

webchick - May 27, 2009 - 02:22
Status:reviewed & tested by the community» needs work
Issue tags:+Needs Documentation

Kick ass! I'm so happy to finally see this fixed! :D

Committed to HEAD! Marking "needs work" until it's documented in the 6.x => 7.x upgrade page.

Ultimately this is up to Gábor, of course, but given what was required to fix this in 7.x, I'm pretty sure we can't backport this to 6.x. It's an API change that requires module developers to make changes to their menu items' access callbacks. In addition to this being a mean thing to ask people 1.5 years after D6's initial release, it will result in hackish "if function_exists" workarounds in order for this to work for people not using the latest versions of Drupal 6. Granted, it'd only affect the handful of modules that define their own top-level admin blocks like OG, Panels, and Project. But still. Stable means stable.

#46

boombatower - May 28, 2009 - 06:30
Status:needs work» needs review

Documentation added: http://drupal.org/node/224333#system_admin_menu_block_access

#47

System Message - May 28, 2009 - 06:35
Status:needs review» needs work

The last submitted patch failed testing.

#48

boombatower - May 28, 2009 - 12:44
Status:needs work» fixed

Guess I'll just mark fixed unless anyone says otherwise.

#49

boombatower - May 28, 2009 - 13:31

#50

System Message - June 11, 2009 - 13:40
Status:fixed» closed

Automatically closed -- issue fixed for 2 weeks with no activity.

#51

jusspitti - July 2, 2009 - 06:54

should any fix be expected for drupal 6? In a different issue maybe?

 
 

Drupal is a registered trademark of Dries Buytaert.