Index: modules/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node.module,v
retrieving revision 1.527
diff -u -p -r1.527 node.module
--- modules/node.module	2 Sep 2005 02:11:41 -0000	1.527
+++ modules/node.module	5 Sep 2005 00:28:02 -0000
@@ -587,7 +587,13 @@ function node_show($node, $cid) {
  * Implementation of hook_perm().
  */
 function node_perm() {
-  return array('administer nodes', 'access content');
+  $perms = array('administer nodes', 'access content');
+  foreach (node_get_types() as $type => $name) {
+    $perms[] = 'view revisions for $type';
+    $perms[] = 'revert revisions for $type';
+  }
+
+  return $perms;
 }
 
 /**
@@ -737,13 +743,12 @@ function node_menu($may_cache) {
           'access' => node_access('delete', $node),
           'weight' => 1,
           'type' => MENU_CALLBACK);
-        if (user_access('administer nodes') && db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', arg(1))) > 1) {
-          $items[] = array('path' => 'node/'. arg(1) .'/revisions', 'title' => t('revisions'),
-            'callback' => 'node_page',
-            'access' => user_access('administer nodes'),
-            'weight' => 2,
-            'type' => MENU_LOCAL_TASK);
-        }
+        $revisions_access = (node_access('view', $node) && (user_access(strtr('view revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) && db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', arg(1))) > 1);
+        $items[] = array('path' => 'node/'. arg(1) .'/revisions', 'title' => t('revisions'),
+          'callback' => 'node_revisions',
+          'access' => $revisions_access,
+          'weight' => 2,
+          'type' => MENU_LOCAL_TASK);
       }
     }
     else if (arg(0) == 'admin' && arg(1) == 'settings' && arg(2) == 'content-types' && is_string(arg(3))) {
@@ -1013,45 +1018,54 @@ function node_types_configure($type = NU
 /**
  * Generate an overview table of older revisions of a node.
  */
-function node_revision_overview($nid) {
-  if (user_access('administer nodes')) {
-    $node = node_load($nid);
-
+function node_revision_overview($node) {
+  if (user_access(strtr('view revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) {
     drupal_set_title(t('Revisions for %title', array('%title' => check_plain($node->title))));
 
-    if ($node->vid) {
-      $header = array('', t('Author'), t('Title'), t('Date'), array('colspan' => '3', 'data' => t('Operations')));
+    $header = array('', t('Author'), t('Title'), t('Date'), array('colspan' => '3', 'data' => t('Operations')));
 
-      $revisions = node_revision_list($node);
+    $revisions = node_revision_list($node);
 
-      $i = 0;
-      foreach ($revisions as $revision) {
-        $row = ++$i;
-        if ($revision->current_vid) {
-          $rows[] = array(
-            array('data' => $row .' '. t('(current)'), 'rowspan' => ($revision->log != '') ? 2 : 1),
-            theme('username', $revision),
-            $revision->title,
-            format_date($revision->timestamp, 'small'),
-            l(t('view'), "node/$node->nid"),
-            '', '');
-        }
-        else {
-          $rows[] = array(
-            array('data' => $row, 'rowspan' => ($revision->log != '') ? 2 : 1),
-            theme('username', $revision),
-            $revision->title,
-            format_date($revision->timestamp, 'small'),
-            l(t('view'), "node/$node->nid/revision/". $revision->vid),
-            l(t('set active'), "node/$node->nid/rollback-revision/". $revision->vid),
-            l(t('delete'), "node/$node->nid/delete-revision/". $revision->vid));
+    $i = 0;
+    $revert_permission = FALSE;
+    if (user_access(strtr('revert revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) {
+      $revert_permission = TRUE;
+    }
+    $delete_permission = FALSE;
+    if (user_access('administer nodes')) {
+      $delete_permission = TRUE;
+    }
+    foreach ($revisions as $revision) {
+      $row = ++$i;
+      if ($revision->current_vid) {
+        $rows[] = array(
+          array('data' => $row .' '. t('(current)'), 'rowspan' => ($revision->log != '') ? 2 : 1),
+          theme('username', $revision),
+          $revision->title,
+          format_date($revision->timestamp, 'small'),
+          l(t('view'), "node/$node->nid"),
+          '', '');
+      }
+      else {
+        $current_row = array(
+          array('data' => $row, 'rowspan' => ($revision->log != '') ? 2 : 1),
+          theme('username', $revision),
+          $revision->title,
+          format_date($revision->timestamp, 'small'),
+          l(t('view'), "node/$node->nid/revisions/$revision->vid/view"));
+        if ($revert_permission) {
+          $current_row[] = l(t('set active'), "node/$node->nid/revisions/$revision->vid/rollback");
         }
-        if ($revision->log != '') {
-          $rows[] = array(array('data' => $revision->log, 'colspan' => 6));
+        if ($delete_permission) {
+          $current_row[] = l(t('delete'), "node/$node->nid/revisions/$revision->vid/delete");
         }
+        $rows[] = $current_row;
+      }
+      if ($revision->log != '') {
+        $rows[] = array(array('data' => $revision->log, 'colspan' => 6));
       }
-      $output .= theme('table', $header, $rows);
     }
+    $output .= theme('table', $header, $rows);
   }
 
   return $output;
@@ -1063,7 +1077,8 @@ function node_revision_overview($nid) {
 function node_revision_rollback($nid, $revision) {
   global $user;
 
-  if (user_access('administer nodes')) {
+  $node = node_load($nid);
+  if (node_access('edit', $node) && user_access(strtr('revert revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) {
     if($title = db_fetch_object(db_query('SELECT title, timestamp FROM {node_revisions} WHERE nid = %d AND vid = %d', $nid, $revision))) {
       db_query('UPDATE {node} SET vid = %d, changed = %d WHERE nid = %d', $revision, $title->timestamp, $nid);
 
@@ -1074,6 +1089,7 @@ function node_revision_rollback($nid, $r
     }
     drupal_goto('node/'. $nid .'/revisions');
   }
+  drupal_access_denied();
 }
 
 /**
@@ -1081,18 +1097,22 @@ function node_revision_rollback($nid, $r
  */
 function node_revision_delete($nid, $revision) {
   if (user_access('administer nodes')) {
-    $count_revisions = db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid));
-    // Don't delete the last revision of the node or the current revision
-    if ($count_revisions > 1) {
-      db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
-      drupal_set_message(t('Deleted revision with the ID %revision.', array('%revision' => theme('placeholder', $revision))));
-    }
-    else {
-      drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
-    }
+    $node = node_load($nid);
+    if (node_access('delete', $node)) {
+      $count_revisions = db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid));
+      // Don't delete the last revision of the node or the current revision
+      if ($count_revisions > 1) {
+        db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision);
+        drupal_set_message(t('Deleted revision with the ID %revision.', array('%revision' => theme('placeholder', $revision))));
+      }
+      else {
+        drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
+      }
 
-    drupal_goto("node/$nid/revisions");
+      drupal_goto("revisions/$nid");
+    }
   }
+  drupal_access_denied();
 }
 
 /**
@@ -1678,7 +1698,7 @@ function node_page() {
       return;
     case 'view':
       if (is_numeric(arg(1))) {
-        $node = node_load(arg(1), $_GET['revision']);
+        $node = node_load(arg(1));
         if ($node->nid) {
           drupal_set_title(check_plain($node->title));
           return node_show($node, arg(2));
@@ -1694,20 +1714,6 @@ function node_page() {
     case 'add':
       return node_add(arg(2));
       break;
-    case 'revisions':
-      if (user_access('administer nodes')) {
-        return node_revision_overview(arg(1));
-      }
-      else {
-        drupal_access_denied();
-      }
-      break;
-    case 'rollback-revision':
-      node_revision_rollback(arg(1), arg(3));
-      break;
-    case 'delete-revision':
-      node_revision_delete(arg(1), arg(3));
-      break;
     case 'edit':
       if (is_numeric(arg(1))) {
         $node = node_load(arg(1));
@@ -1723,18 +1729,6 @@ function node_page() {
         }
       }
       break;
-    case 'revision':
-      if (is_numeric(arg(1)) && is_numeric(arg(3))) {
-        $node = node_load(arg(1), arg(3));
-        if ($node->nid) {
-          drupal_set_title(t('Revision of %title', array('%title' => theme('placeholder', $node->title))));
-          print theme('page', node_show($node, arg(2)));
-        }
-        else {
-          drupal_not_found();
-        }
-      }
-      break;
     case t('Preview'):
       $edit = node_validate($edit);
       drupal_set_title(t('Preview'));
@@ -1769,6 +1763,51 @@ function node_page() {
 }
 
 /**
+ * Menu callback for revisions related activities.
+ */
+function node_revisions() {
+  if (is_numeric(arg(1)) && arg(2) == 'revisions') {
+    $op = arg(4) ? arg(4) : 'overview';
+    switch ($op) {
+      case 'overview':
+        $node = node_load(arg(1));
+        if (node_access('view', $node) && user_access(strtr('view revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) {
+          return node_revision_overview($node);
+        }
+        else {
+          drupal_access_denied();
+        }
+        break;
+      case 'view':
+        if (is_numeric(arg(3))) {
+          $node = node_load(arg(1), arg(3));
+          if ($node->nid) {
+            if (node_access($node, 'view') && user_access(strtr('view revisions for %type', array('%type' => $node->type))) || user_access('administer nodes')) {
+              drupal_set_title(t('Revision of %title from %date', array('%title' => theme('placeholder', $node->title), '%date' => format_date($node->revision_timestamp))));
+              return node_show($node, arg(2));
+            }
+            else {
+              drupal_access_denied();
+            }
+          }
+        }
+        drupal_not_found();
+        break;
+      case 'rollback':
+        node_revision_rollback(arg(1), arg(3));
+        break;
+      case 'delete':
+        node_revision_delete(arg(1), arg(3));
+        break;
+      default:
+        drupal_not_found();
+        break;
+    }
+  }
+  drupal_not_found();
+}
+
+/**
  * Menu callback; the page for deleting a single node.
  */
 function node_delete_page() {
