? ./sites/default/files ? ./sites/default/settings.php Index: ./modules/node/node.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.admin.inc,v retrieving revision 1.38 diff -u -p -r1.38 node.admin.inc --- ./modules/node/node.admin.inc 3 Feb 2009 18:55:30 -0000 1.38 +++ ./modules/node/node.admin.inc 10 Feb 2009 02:48:34 -0000 @@ -166,8 +166,11 @@ function node_filters() { /** * Build query for node administration filters based on session. + * + * @param $for_user + * TRUE if building a list of nodes owned by the current user. */ -function node_build_filter_query() { +function node_build_filter_query($for_user) { $filters = node_filters(); // Build query @@ -195,6 +198,13 @@ function node_build_filter_query() { } $args[] = $value; } + + // Filter for a specific user at 'My content'. + if ($for_user) { + $where[] = 'n.uid = %d'; + $args[] = $GLOBALS['user']->uid; + } + $where = count($where) ? 'WHERE ' . implode(' AND ', $where) : ''; return array('where' => $where, 'join' => $join, 'args' => $args); @@ -440,30 +450,39 @@ function _node_mass_update_batch_finishe /** * Menu callback: content administration. + * + * @param $for_user + * TRUE if building a list of nodes owned by the current user. */ -function node_admin_content($form_state) { +function node_admin_content($form_state, $for_user = FALSE) { if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') { - return node_multiple_delete_confirm($form_state, array_filter($form_state['values']['nodes'])); + return node_multiple_delete_confirm($form_state, array_filter($form_state['values']['nodes']), $for_user); } $form = node_filter_form(); $form['#theme'] = 'node_filter_form'; - $form['admin'] = node_admin_nodes(); + + $form['admin'] = node_admin_nodes($for_user); return $form; } /** * Form builder: Builds the node administration overview. + * + * @param $for_user + * TRUE if building a list of nodes owned by the current user. */ -function node_admin_nodes() { +function node_admin_nodes($for_user = FALSE) { // Enable language column if translation module is enabled // or if we have any node with language. - $multilanguage = (module_exists('translation') || db_result(db_query("SELECT COUNT(*) FROM {node} WHERE language != ''"))); + $multilanguage = (module_exists('translation') || db_query("SELECT COUNT(*) FROM {node} WHERE language != ''")->fetchField()); // Build the sortable table header. $header = array(); - $header[] = theme('table_select_header_cell'); + if (user_access('administer nodes') && user_access('bypass node access')) { + $header[] = theme('table_select_header_cell'); + } $header[] = array('data' => t('Title'), 'field' => 'n.title'); $header[] = array('data' => t('Type'), 'field' => 'n.type'); $header[] = array('data' => t('Author'), 'field' => 'u.name'); @@ -480,10 +499,11 @@ function node_admin_nodes() { ); // Build the query and load the nodes we want to display. - $filter = node_build_filter_query(); + $filter = node_build_filter_query($for_user); $sort = tablesort_sql($header, '', 'n.changed DESC'); - $result = pager_query(db_rewrite_sql('SELECT n.*, u.name FROM {node} n '. $filter['join'] .' INNER JOIN {users} u ON n.uid = u.uid '. $filter['where'] . $sort), 50, 0, NULL, $filter['args']); + $nids = pager_query(db_rewrite_sql('SELECT n.nid FROM {node} n ' . $filter['join'] . $filter['where'] . $sort), 50, 0, NULL, $filter['args'])->fetchCol(); + $nodes = node_load_multiple($nids); // Build the 'Update options' form. $form['options'] = array( @@ -491,6 +511,7 @@ function node_admin_nodes() { '#title' => t('Update options'), '#prefix' => '
', '#suffix' => '
', + '#access' => user_access('administer nodes') && user_access('bypass node access'), ); $options = array(); foreach (module_invoke_all('node_operations') as $operation => $array) { @@ -509,9 +530,9 @@ function node_admin_nodes() { $languages = language_list(); $destination = drupal_get_destination(); - $nodes = array(); - while ($node = db_fetch_object($result)) { - $nodes[$node->nid] = ''; + $nids = array(); + foreach ($nodes as $node) { + $nids[$node->nid] = ''; $options = empty($node->language) ? array() : array('language' => $languages[$node->language]); $form['title'][$node->nid] = array('#markup' => l($node->title, 'node/' . $node->nid, $options) . ' ' . theme('mark', node_mark($node->nid, $node->changed))); $form['name'][$node->nid] = array('#markup' => check_plain(node_get_types('name', $node))); @@ -521,12 +542,14 @@ function node_admin_nodes() { if ($multilanguage) { $form['language'][$node->nid] = array('#markup' => empty($node->language) ? t('Language neutral') : t($languages[$node->language]->name)); } - $form['operations'][$node->nid] = array('#markup' => l(t('edit'), 'node/' . $node->nid . '/edit', array('query' => $destination))); + $form['operations'][$node->nid] = array('#markup' => l(t('edit'), 'node/' . $node->nid . '/edit', array('query' => $destination)), '#access' => node_access('update', $node)); } $form['nodes'] = array( '#type' => 'checkboxes', - '#options' => $nodes, + '#options' => $nids, + '#access' => user_access('administer nodes') && user_access('bypass node access'), ); + $form['pager'] = array('#markup' => theme('pager', NULL, 50, 0)); $form['#theme'] = 'node_admin_nodes'; return $form; @@ -591,7 +614,10 @@ function theme_node_admin_nodes($form) { $rows = array(); foreach (element_children($form['title']) as $key) { $row = array(); - $row[] = drupal_render($form['nodes'][$key]); + + if (user_access('administer nodes') && user_access('bypass node access')) { + $row[] = drupal_render($form['nodes'][$key]); + } $row[] = drupal_render($form['title'][$key]); $row[] = drupal_render($form['name'][$key]); $row[] = drupal_render($form['username'][$key]); @@ -621,7 +647,7 @@ function theme_node_admin_nodes($form) { return $output; } -function node_multiple_delete_confirm(&$form_state, $nodes) { +function node_multiple_delete_confirm(&$form_state, $nodes, $for_user = FALSE) { $form['nodes'] = array('#prefix' => '', '#tree' => TRUE); // array_filter returns only elements with TRUE values @@ -635,10 +661,13 @@ function node_multiple_delete_confirm(&$ ); } $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); + + // Ensure users stay on the same page when deleting or mass updating content. + $form['#redirect'] = ($for_user ? 'admin/content/node' : 'admin/content/node/all'); $form['#submit'][] = 'node_multiple_delete_confirm_submit'; return confirm_form($form, t('Are you sure you want to delete these items?'), - 'admin/content/node', t('This action cannot be undone.'), + $for_user ? 'admin/content/node' : 'admin/content/node/all', t('This action cannot be undone.'), t('Delete all'), t('Cancel')); } Index: ./modules/node/node.install =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.install,v retrieving revision 1.11 diff -u -p -r1.11 node.install --- ./modules/node/node.install 21 Jan 2009 16:58:42 -0000 1.11 +++ ./modules/node/node.install 10 Feb 2009 02:48:34 -0000 @@ -417,5 +417,13 @@ function node_update_7002() { } /** + * Add the 'View content' link to the navigation menu. + */ +function node_update_7003() { + $link = array('link_path' => 'admin/content/node', 'link_title' => 'View content', 'menu_name' => 'navigation', 'plid' => 0, 'weight' => '3'); + menu_link_save($link); +} + +/** * End of 6.x to 7.x updates */ Index: ./modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.1023 diff -u -p -r1.1023 node.module --- ./modules/node/node.module 6 Feb 2009 16:25:08 -0000 1.1023 +++ ./modules/node/node.module 10 Feb 2009 02:48:34 -0000 @@ -71,6 +71,7 @@ function node_help($path, $arg) { $output .= '

' . t('For more information, see the online handbook entry for Node module.', array('@node' => 'http://drupal.org/handbook/modules/node/')) . '

'; return $output; case 'admin/content/node': + case 'admin/content/node/all': return ' '; // Return a non-null value so that the 'more help' link is shown. case 'admin/build/types': return '

' . t('Below is a list of all the content types on your site. All posts that exist on your site are instances of one of these content types.') . '

'; @@ -1330,6 +1331,10 @@ function node_perm() { 'title' => t('Access content'), 'description' => t('View published content.'), ), + 'access content overview' => array( + 'title' => t('Access content overview'), + 'description' => t('List and filter available content from the administrative content pages.'), + ), 'bypass node access' => array( 'title' => t('Bypass node access'), 'description' => t('View, edit and delete all site content. Users with this permission will bypass any content-related access control. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))), @@ -1682,14 +1687,22 @@ function node_menu() { 'title' => 'Content', 'description' => "View, edit, and delete your site's content.", 'page callback' => 'drupal_get_form', - 'page arguments' => array('node_admin_content'), - 'access arguments' => array('administer nodes'), + 'page arguments' => array('node_admin_content', TRUE), + 'access callback' => 'node_content_page_access', ); - $items['admin/content/node/overview'] = array( - 'title' => 'List', + $items['admin/content/node/user'] = array( + 'title' => 'My content', 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10, + ); + + $items['admin/content/node/all'] = array( + 'title' => 'All content', + 'description' => "View, edit, and delete your site's content.", + 'page arguments' => array('node_admin_content'), + 'access callback' => 'node_content_page_access', + 'type' => MENU_LOCAL_TASK, + 'weight' => 5, ); $items['admin/content/node-settings'] = array( @@ -2350,6 +2363,33 @@ function node_access($op, $node, $accoun } /** + * Checks whether the current user has access to the content list page. + */ +function node_content_page_access() { + // Users with administer nodes automatically get this page. + if (user_access('administer nodes')) { + return TRUE; + } + + // If the user has no permission to access content, deny. + if (!user_access('access content') || !user_access('access content overview')) { + return FALSE; + } + + $types = node_get_types('types'); + foreach ($types as $type) { + $permissions = node_list_permissions(check_plain($type->type)); + foreach (array_keys($permissions) as $permission) { + if (user_access($permission)) { + return TRUE; + } + } + } + + return FALSE; +} + +/** * Generate an SQL join clause for use in fetching a node listing. * * @param $node_alias Index: ./modules/node/node.test =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.test,v retrieving revision 1.16 diff -u -p -r1.16 node.test --- ./modules/node/node.test 28 Jan 2009 07:34:30 -0000 1.16 +++ ./modules/node/node.test 10 Feb 2009 02:48:34 -0000 @@ -635,3 +635,48 @@ class NodeRSSContentTestCase extends Dru $this->assertText($test_text, t('Extra node content appears in RSS feed.')); } } + +class ContentAdminPagesCase extends DrupalWebTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('Content Admin Pages'), + 'description' => t('Create users and content to test the content admin pages functionality.'), + 'group' => t('Node'), + ); + } + function setUp() { + parent::setUp(); + $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer nodes', 'bypass node access')); + $this->base_user = $this->drupalCreateUser(array('access content overview', 'edit own page content', 'create page content')); + } + function testContentAdminPages() { + $this->drupalLogin($this->admin_user); + + // Ensure the admin user can edit any content. + $created_node = $this->drupalCreateNode(array('type' => 'page')); + $this->drupalGet('admin/content/node'); + $this->assertResponse(200); + $this->drupalGet('admin/content/node/all'); + $this->assertResponse(200); + $this->assertText('edit', t('Admin user has edit link.')); + $this->drupalLogout(); + + // Ensure users don't see edit links for content they don't have rights to edit. + $this->drupalLogin($this->base_user); + $this->drupalGet('admin/content/node/all'); + $this->assertResponse(200); + $this->assertText($created_node->title, t('Edit links disabled without edit permissions.')); + $this->assertNoText('edit', t('Edit links do not show up for users without rights.')); + + // Ensure users content shows up on their 'My Content' page, and they have edit links. + $user_node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->base_user->uid)); + $this->drupalGet('admin/content/node'); + $this->assertText($user_node->title, t("User's own content is displayed.")); + $this->assertNoText($created_node->title, t('Nodes not belonging to user are not displayed.')); + + } +} + Index: ./modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.306 diff -u -p -r1.306 system.install --- ./modules/system/system.install 3 Feb 2009 12:30:14 -0000 1.306 +++ ./modules/system/system.install 10 Feb 2009 02:48:35 -0000 @@ -364,6 +364,7 @@ function system_install() { // Authenticated role permissions. db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'access comments'); db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'access content'); + db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'access content overview'); db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'post comments'); db_query("INSERT INTO {role_permission} (rid, permission) VALUES (%d, '%s')", 2, 'post comments without approval'); Index: ./profiles/default/default.profile =================================================================== RCS file: /cvs/drupal/drupal/profiles/default/default.profile,v retrieving revision 1.37 diff -u -p -r1.37 default.profile --- ./profiles/default/default.profile 3 Feb 2009 12:30:14 -0000 1.37 +++ ./profiles/default/default.profile 10 Feb 2009 02:48:35 -0000 @@ -158,6 +158,8 @@ function default_profile_tasks(&$task, $ menu_link_save($link); $link = array('link_path' => 'admin/build/menu-customize/secondary-menu/add', 'link_title' => 'Add a secondary menu link', 'menu_name' => 'secondary-menu'); menu_link_save($link); + $link = array('link_path' => 'admin/content/node', 'link_title' => 'View content', 'menu_name' => 'navigation', 'plid' => 0, 'weight' => '3'); + menu_link_save($link); } /**