From 8b3422615195d9201adcd9730f034fb87dee1e84 Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros@gmail.com>
Date: Sun, 24 Apr 2011 17:55:55 +0200
Subject: [PATCH] Issue #1137052 by Berdir: Fixed argument map of parent router item is used when checking access for local tasks.

---
 includes/menu.inc                         |   13 ++++++++-
 modules/simpletest/tests/menu.test        |   27 ++++++++++++++++++
 modules/simpletest/tests/menu_test.module |   42 +++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 1 deletions(-)

diff --git a/includes/menu.inc b/includes/menu.inc
index 2a8c80c..30def2d 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1854,12 +1854,23 @@ function menu_local_tasks($level = 0) {
       ->orderBy('weight')
       ->orderBy('title')
       ->execute();
-    $map = $router_item['original_map'];
+    $original_map = $router_item['original_map'];
+    $map_elements_count = count($original_map);
+    // Extract the part of the map of the tab_parent, if existing. This is
+    // required to override the arguments of the currently active local_task
+    // if it is not the default.
+    if (!empty($router_item['tab_parent'])) {
+      $map_elements_count = substr_count($router_item['tab_parent'], '/') + 1;
+      $original_map = array_slice($original_map, 0, $map_elements_count);
+    }
     $children = array();
     $tasks = array();
     $root_path = $router_item['path'];
 
     foreach ($result as $item) {
+      // Build the map for this local task, start with the original map and then
+      // append the additional local task path elements.
+      $map = array_merge($original_map, array_slice(arg(NULL, $item['path']), $map_elements_count));
       _menu_translate($item, $map, TRUE);
       if ($item['tab_parent']) {
         // All tabs, but not the root page.
diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test
index 2578beb..585dab3 100644
--- a/modules/simpletest/tests/menu.test
+++ b/modules/simpletest/tests/menu.test
@@ -34,6 +34,33 @@ class MenuRouterTestCase extends DrupalWebTestCase {
   }
 
   /**
+   * Test local tasks with an access callback.
+   */
+  function testLocalTasksWithAccessCallback() {
+    $this->drupalGet('menu-test/local-tasks');
+
+    $this->assertText('This is menu_test_callback().', t('Raw text found on the page'));
+
+    // Verify that only the first and third local tasks are shown.
+    $this->assertText(t('First local task'), t('First local task is shown'));
+    $this->assertNoText(t('Second local task'), t('Second local task is not shown'));
+    $this->assertText(t('Third local task'), t('Third local task is shown'));
+
+    // Click on third local task and repeat tests.
+    $this->clickLink(t('Third local task'));
+    $this->assertText('This is menu_test_callback().', t('Raw text found on the page'));
+
+    // Verify that only the first and third local tasks are shown.
+    $this->assertText(t('First local task'), t('First local task is shown'));
+    $this->assertNoText(t('Second local task'), t('Second local task is not shown'));
+    $this->assertText(t('Third local task'), t('Third local task is shown'));
+
+    // Got the second local task and make sure that access is denied.
+    $this->drupalGet('menu-test/local-tasks/2');
+    $this->assertText(t('Access denied'), t('Access to second local task is denied'));
+  }
+
+  /**
    * Tests page title of MENU_CALLBACKs.
    */
   function testTitleMenuCallback() {
diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module
index 3046a04..5e896df 100644
--- a/modules/simpletest/tests/menu_test.module
+++ b/modules/simpletest/tests/menu_test.module
@@ -317,10 +317,52 @@ function menu_test_menu() {
     'access callback' => TRUE,
   );
 
+  $items['menu-test/local-tasks'] = array(
+    'title' => 'Local task access check',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+
+  $items['menu-test/local-tasks/1'] = array(
+    'title' => 'First local task',
+    'page callback' => 'menu_test_callback',
+    'access callback' => 'menu_test_access_callback_local_task',
+    'access arguments' => array(2),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+
+  $items['menu-test/local-tasks/2'] = array(
+    'title' => 'Second local task',
+    'page callback' => 'menu_test_callback',
+    'access callback' => 'menu_test_access_callback_local_task',
+    'access arguments' => array(2),
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  $items['menu-test/local-tasks/3'] = array(
+    'title' => 'Third local task',
+    'page callback' => 'menu_test_callback',
+    'access callback' => 'menu_test_access_callback_local_task',
+    'access arguments' => array(2),
+    'type' => MENU_LOCAL_TASK,
+  );
+
   return $items;
 }
 
 /**
+ * Check access for local tasks with an argument.
+ * @param $id
+ *   Argument passed in from the url.
+ *
+ * @return
+ *   TRUE for all ids except 2.
+ */
+function menu_test_access_callback_local_task($id) {
+  return $id != '2';
+}
+
+/**
  * Dummy argument loader for hook_menu() to point to.
  */
 function menu_test_argument_load($arg1) {
-- 
1.7.4.1

