Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1079
diff -u -p -r1.1079 node.module
--- modules/node/node.module	5 Jul 2009 18:00:09 -0000	1.1079
+++ modules/node/node.module	7 Jul 2009 03:23:55 -0000
@@ -1293,6 +1293,10 @@ function node_permission() {
       'title' => t('Delete revisions'),
       'description' => t('Delete content revisions.'),
     ),
+    'view own unpublished content' => array(
+      'title' => t('View own unpublished content'),
+      'description' => t('View unpublished content created by the user'),
+    ),
   );
 
   foreach (node_type_get_types() as $type) {
@@ -2270,17 +2274,22 @@ function node_access($op, $node, $accoun
     return $access;
   }
 
+  // Check if authors can view their own unpublished nodes.
+  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
+    return TRUE;
+  }
+
   // If the module did not override the access rights, use those set in the
   // node_access table.
-  if ($op != 'create' && $node->nid && $node->status) {
+  if ($op != 'create' && $node->nid) {
     $query = db_select('node_access');
     $query->addExpression('COUNT(*)');
-    $query
-      ->condition(db_or()
-        ->condition('nid', 0)
-        ->condition('nid', $node->nid)
-      )
-      ->condition('grant_' . $op, 1, '>=');
+    $query->condition('grant_' . $op, 1, '>=');
+    $nids = db_or()->condition('nid', $node->nid);
+    if ($node->status) {
+      $nids->condition('nid', 0);
+    }
+    $query->condition($nids);
 
     $grants = db_or();
     foreach (node_access_grants($op, $account) as $realm => $gids) {
@@ -2299,11 +2308,6 @@ function node_access($op, $node, $accoun
       ->fetchField();
   }
 
-  // Let authors view their own nodes.
-  if ($op == 'view' && $account->uid == $node->uid && $account->uid != 0) {
-    return TRUE;
-  }
-
   return FALSE;
 }
 
Index: modules/node/node.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.test,v
retrieving revision 1.34
diff -u -p -r1.34 node.test
--- modules/node/node.test	1 Jul 2009 12:10:32 -0000	1.34
+++ modules/node/node.test	7 Jul 2009 03:23:55 -0000
@@ -392,7 +392,7 @@ class SummaryLengthTestCase extends Drup
     // The node teaser when it has 600 characters in length
     $expected = 'What is a Drupalism?';
     $this->assertRaw($expected, t('Check that the summary is 600 characters in length'), 'Node');
-    
+
     // Edit the teaser lenght for 'page' content type
     $edit = array (
       'teaser_length' => 200,
@@ -587,13 +587,80 @@ class NodeRSSContentTestCase extends Dru
 }
 
 /**
- * Test case to verify hook_node_access_records_alter functionality.
+ * Test case to verify basic node_access functionality.
+ * @todo Cover hook_access in a separate test class.
+ * hook_node_access_records is covered in another test class.
  */
-class NodeAccessRecordsAlterUnitTest extends DrupalWebTestCase {
+class NodeAccessUnitTest extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
-      'name' => t('Node access records alter'),
-      'description' => t('Test hook_node_access_records_alter when acquiring grants.'),
+      'name' => t('Node access'),
+      'description' => t('Test node_access function'),
+      'group' => t('Node'),
+    );
+  }
+
+  /**
+   * Asserts node_access correctly grants or denies access.
+   */
+  function assertNodeAccess($ops, $node, $account) {
+    foreach ($ops as $op => $result) {
+      $msg = t("node_access returns @result with operation '@op'.", array('@result' => $result ? 'true' : 'false', '@op' => $op));
+      $this->assertEqual($result, node_access($op, $node, $account), $msg);
+    }
+  }
+
+  function setUp() {
+    parent::setUp();
+    // Clear permissions for authenticated users.
+    db_delete('role_permission')
+      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
+      ->execute();
+  }
+
+  /**
+   * Runs basic tests for node_access function.
+   */
+  function testNodeAccess() {
+    // Ensures user without 'access content' permission can do nothing.
+    $web_user1 = $this->drupalCreateUser(array('create page content', 'edit any page content', 'delete any page content'));
+    $node1 = $this->drupalCreateNode(array('type' => 'page'));
+    $this->assertNodeAccess(array('create' => FALSE), 'page', $web_user1);
+    $this->assertNodeAccess(array('view' => FALSE, 'update' => FALSE, 'delete' => FALSE), $node1, $web_user1);
+
+    // Ensures user with 'bypass node access' permission can do everything.
+    $web_user2 = $this->drupalCreateUser(array('bypass node access'));
+    $node2 = $this->drupalCreateNode(array('type' => 'page'));
+    $this->assertNodeAccess(array('create' => TRUE), 'page', $web_user2);
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $node2, $web_user2);
+
+    // User cannot 'view own unpublished content'.
+    $web_user3 = $this->drupalCreateUser(array('access content'));
+    $node3 = $this->drupalCreateNode(array('status' => 0, 'uid' => $web_user3->uid));
+    $this->assertNodeAccess(array('view' => FALSE), $node3, $web_user3);
+
+    // User can 'view own unpublished content', but another user cannot.
+    $web_user4 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
+    $web_user5 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
+    $node4 = $this->drupalCreateNode(array('status' => 0, 'uid' => $web_user4->uid));
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE), $node4, $web_user4);
+    $this->assertNodeAccess(array('view' => FALSE), $node4, $web_user5);
+
+    // Tests the default access provided for a published node.
+    $node5 = $this->drupalCreateNode();
+    $this->assertNodeAccess(array('create' => FALSE), 'page', $web_user3);
+    $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $node5, $web_user3);
+  }
+}
+
+/**
+ * Test case to verify hook_node_access_records functionality.
+ */
+class NodeAccessRecordsUnitTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Node access records'),
+      'description' => t('Test hook_node_access_records when acquiring grants.'),
       'group' => t('Node'),
     );
   }
@@ -608,7 +675,7 @@ class NodeAccessRecordsAlterUnitTest ext
   /**
    * Create a node and test the creation of node access rules.
    */
-  function testGrantAlter() {
+  function testNodeAccessRecords() {
     // Create an article node.
     $node1 = $this->drupalCreateNode(array('type' => 'article'));
     $this->assertTrue(node_load($node1->nid), t('Article node created.'));
@@ -629,13 +696,23 @@ class NodeAccessRecordsAlterUnitTest ext
     $this->assertEqual($records[0]->realm, 'test_page_realm', t('Grant with page_realm acquired for node without alteration.'));
     $this->assertEqual($records[0]->gid, 1, t('Grant with gid = 1 acquired for node without alteration.'));
 
+    // Create an unpromoted, unpublished page node.
+    $node3 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0, 'status' => 0));
+    $this->assertTrue(node_load($node3->nid), t('Unpromoted, unpublished page node created.'));
+
+    // Check to see if grants added by node_test_node_access_records made it in.
+    $records = db_query('SELECT realm, gid FROM {node_access} WHERE nid = %d', $node3->nid)->fetchAll();
+    $this->assertEqual(count($records), 1, t('Returned the correct number of rows.'));
+    $this->assertEqual($records[0]->realm, 'test_page_realm', t('Grant with page_realm acquired for node without alteration.'));
+    $this->assertEqual($records[0]->gid, 1, t('Grant with gid = 1 acquired for node without alteration.'));
+
     // Create a promoted page node.
-    $node3 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
-    $this->assertTrue(node_load($node3->nid), t('Promoted page node created.'));
+    $node4 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
+    $this->assertTrue(node_load($node4->nid), t('Promoted page node created.'));
 
     // Check to see if grant added by node_test_node_access_records was altered
     // by node_test_node_access_records_alter.
-    $records = db_query('SELECT realm, gid FROM {node_access} WHERE nid = %d', $node3->nid)->fetchAll();
+    $records = db_query('SELECT realm, gid FROM {node_access} WHERE nid = %d', $node4->nid)->fetchAll();
     $this->assertEqual(count($records), 1, t('Returned the correct number of rows.'));
     $this->assertEqual($records[0]->realm, 'test_alter_realm', t('Altered grant with alter_realm acquired for node.'));
     $this->assertEqual($records[0]->gid, 2, t('Altered grant with gid = 2 acquired for node.'));
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.353
diff -u -p -r1.353 system.install
--- modules/system/system.install	4 Jul 2009 14:45:36 -0000	1.353
+++ modules/system/system.install	7 Jul 2009 03:23:55 -0000
@@ -407,7 +407,7 @@ function system_install() {
   ));
 
   // Authenticated role permissions.
-  foreach (array('access comments', 'access content', 'post comments', 'post comments without approval') as $permission) {
+  foreach (array('access comments', 'access content', 'post comments', 'post comments without approval', 'view own unpublished content') as $permission) {
     $query->values(array(
       'rid' => DRUPAL_AUTHENTICATED_RID,
       'permission' => $permission,
@@ -2226,6 +2226,21 @@ function system_update_7028() {
 }
 
 /**
+ * Add new 'view own unpublished content' permission for authenticated users.
+ * Preserves legacy behavior from Drupal 6.x.
+ */
+function system_update_7029() {
+  $ret = array();
+  db_insert('role_permission')
+    ->fields(array(
+      'rid' => DRUPAL_AUTHENTICATED_RID,
+      'permission' => 'view own unpublished content',
+    ))
+    ->execute();
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */
