Index: og_user_roles.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og_user_roles/og_user_roles.module,v retrieving revision 1.40 diff -u -p -r1.40 og_user_roles.module --- og_user_roles.module 14 Aug 2009 12:08:06 -0000 1.40 +++ og_user_roles.module 14 Aug 2009 14:45:19 -0000 @@ -180,7 +180,7 @@ function og_user_roles_determine_context * * In Drupal 7, this fork can probably be replaced with * @code - * drupal_static_reset('menu_get_item'); + * drupal_static_reset('menu_get_item'); * @endcode * * @see menu_get_item() @@ -199,7 +199,8 @@ function og_user_roles_menu_get_item($pa list($ancestors, $placeholders) = menu_get_ancestors($parts); if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {menu_router} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) { - $map = _menu_translate($router_item, $original_map); + // OGUR: Allow privilege escalation; do not invoke access callbacks. + $map = og_user_roles_menu_translate($router_item, $original_map); if ($map === FALSE) { $router_items[$path] = FALSE; return FALSE; @@ -216,6 +217,64 @@ function og_user_roles_menu_get_item($pa } /** + * Handles dynamic path translation and menu access control. + * + * Certain menu access callbacks (like _node_revision_access()) statically cache + * the result of the access check for performance. We only want to retrieve and + * determine the group context in og_user_roles_init(), resp. + * og_user_roles_menu_get_item(), where no additional roles have been granted + * yet. _menu_translate() would normally also invoke the access callback for the + * current page. Therefore, certain menu access callbacks, which statically + * cache their result, would return that result in subsequent invocations (i.e. + * FALSE when the user does not have permissions). + * + * Since OG user roles only wants to retrieve context and all of the regular + * menu system's behavior is and should not be modified, we simply skip the + * access check in this fork. + * + * In Drupal 7, this wrapper can probably be replaced with (or similar): + * @code + * drupal_static_reset('_node_revision_access'); + * @endcode + * + * @see _menu_translate() + * @see og_user_roles_menu_get_item() + */ +function og_user_roles_menu_translate(&$router_item, $map, $to_arg = FALSE) { + if ($to_arg) { + // Fill in missing path elements, such as the current uid. + _menu_link_map_translate($map, $router_item['to_arg_functions']); + } + // The $path_map saves the pieces of the path as strings, while elements in + // $map may be replaced with loaded objects. + $path_map = $map; + if (!_menu_load_objects($router_item, $map)) { + // An error occurred loading an object. + $router_item['access'] = FALSE; + return FALSE; + } + + // Generate the link path for the page request or local tasks. + $link_map = explode('/', $router_item['path']); + for ($i = 0; $i < $router_item['number_parts']; $i++) { + if ($link_map[$i] == '%') { + $link_map[$i] = $path_map[$i]; + } + } + $router_item['href'] = implode('/', $link_map); + $router_item['options'] = array(); + // OGUR: Allow privilege escalation; do not invoke access callbacks. + //_menu_check_access($router_item, $map); + + // For performance, don't localize an item the user can't access. + if (!empty($router_item['access'])) { + _menu_item_localize($router_item, $map); + } + + return $map; +} + +/** * Get a loaded object from a router item. * * @see menu_get_object() Index: tests/og_user_roles.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/og_user_roles/tests/og_user_roles.test,v retrieving revision 1.3 diff -u -p -r1.3 og_user_roles.test --- tests/og_user_roles.test 14 Aug 2009 12:00:30 -0000 1.3 +++ tests/og_user_roles.test 14 Aug 2009 15:46:18 -0000 @@ -12,7 +12,7 @@ class OGUserRolesTestCase extends OgTest public static function getInfo() { return array( 'name' => 'OG User Roles', - 'description' => 'Add, edit and delete custom block. Configure and move a module-defined block.', + 'description' => 'Test privilege escalation of Organic Groups User Roles.', 'group' => 'Organic groups', ); } @@ -35,6 +35,12 @@ class OGUserRolesTestCase extends OgTest // Create a group post content type. $this->og_post_type = $this->drupalCreateContentType(); variable_set('og_content_type_usage_' . $this->og_post_type->name, 'group_post'); + // Enable revisions for group post content type. + $edit = array( + 'node_options[revision]' => 1, + ); + $type_url_str = str_replace('_', '-', $this->og_post_type->name); + $this->drupalPost('admin/content/node-type/' . $type_url_str, $edit, t('Save content type')); // Create two groups and a post for each group. $this->gid1 = $this->addOgGroup($this->og_group_type->name); @@ -64,11 +70,13 @@ class OGUserRolesTestCase extends OgTest ); $this->drupalPost('admin/og/og_user_roles', $edit, 'Save configuration'); - // Allow users in role 'ogur' to alter stories and post comments. + // Allow users in role 'ogur' to create/edit/delete stories, view revisions, + // and post comments. $edit = array( $this->role_ogur . '[create ' . $this->og_post_type->name . ' content]' => 1, $this->role_ogur . '[delete any ' . $this->og_post_type->name . ' content]' => 1, $this->role_ogur . '[edit any ' . $this->og_post_type->name . ' content]' => 1, + $this->role_ogur . '[view revisions]' => 1, $this->role_ogur . '[post comments]' => 1, $this->role_ogur . '[post comments without approval]' => 1, ); @@ -108,6 +116,7 @@ class OGUserRolesTestCase extends OgTest // Verify that user cannot edit group post belonging to second group. $this->drupalGet('node/' . $node2->nid); $this->assertNoLink('Edit'); + $this->assertNoLink('Revisions'); // Verify that user can edit group post belonging to first group. $this->drupalGet('node/' . $node1->nid); @@ -116,6 +125,10 @@ class OGUserRolesTestCase extends OgTest $this->drupalPost(NULL, array(), 'Save'); $t_args = array('@type' => $this->og_post_type->name, '%title' => $node1->title); $this->assertRaw(t('@type %title has been updated.', $t_args), 'User can update post in group.'); + + // Verify that user can access revisions for first group post. + $this->assertLink('Revisions'); + $this->clickLink('Revisions'); } /**