? node_access.patch
? modules/forum_access
? modules/node/node.install
? sites/test1.logrus.com
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.660
diff -u -p -r1.660 node.module
--- modules/node/node.module	19 Jul 2006 07:15:35 -0000	1.660
+++ modules/node/node.module	25 Jul 2006 04:42:12 -0000
@@ -489,6 +489,9 @@ function node_save(&$node) {
     node_invoke_nodeapi($node, 'update');
   }
 
+  // Update the node access table for this node.
+  node_access_acquire_grants($node);
+
   // Clear the cache so an anonymous poster can see the node being added or updated.
   cache_clear_all();
 }
@@ -844,6 +847,9 @@ function node_menu($may_cache) {
     $items[] = array('path' => 'admin/settings/node', 'title' => t('posts'),
       'callback' => 'node_configure',
       'access' => user_access('administer nodes'));
+    $items[] = array('path' => 'admin/settings/node-access', 'title' => t('node access'),
+      'callback' => 'node_access_reset_page',
+      'access' => user_access('administer nodes'));
     $items[] = array('path' => 'admin/settings/content-types', 'title' => t('content types'),
       'callback' => 'node_types_configure',
       'access' => user_access('administer nodes'));
@@ -2471,6 +2477,127 @@ function node_db_rewrite_sql($query, $pr
 }
 
 /**
+ * This function will call module invoke to get a list of grants and then
+ * write them to the database. It is called at node save, and should be
+ * called by modules whenever something other than a node_save causes
+ * the permissions on a node to change.
+ *
+ * This function is the only function that should write to the node_access
+ * table.
+ *
+ * @param $node
+ *   The $node to acquire grants for.
+ */
+function node_access_acquire_grants($node) {
+  // Unfortunately hook_node_grants is misnamed. I think it should be
+  // hook_node_user_grants.
+  $grants = module_invoke_all('node_access_records', $node);
+  if (!$grants) {
+    $grants[] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0);
+  }
+  else {
+    // retain grants by highest priority
+    $grant_by_priority = array();
+    foreach ($grants as $g) {
+      $grant_by_priority[intval($g['priority'])][] = $g;
+    }
+    krsort($grant_by_priority);
+    $grants = current($grant_by_priority);
+  }
+
+  node_access_write_grants($node, $grants);
+}
+
+/**
+ * This function will write a list of grants to the database, deleting
+ * any pre-existing grants. If a realm is provided, it will only
+ * delete grants from that realm, but it will always delete a grant
+ * from the 'all' realm. Modules which utilize node_access can
+ * use this function when doing mass updates due to widespread permission
+ * changes.
+ *
+ * @param $node
+ *   The $node being written to. All that is necessary is that it contain a nid.
+ * @param $grants
+ *   A list of grants to write. Each grant is an array that must contain the
+ *   following keys: realm, gid, grant_view, grant_update, grant_delete.
+ *   The realm is specified by a particular module; the gid is as well, and
+ *   is a module-defined id to define grant privileges. each grant_* field
+ *   is a boolean value.
+ * @param $realm
+ *   If provided, only read/write grants for that realm.
+ * @param $delete
+ *   If false, do not delete records. This is only for optimization purposes,
+ *   and assumes the caller has already performed a mass delete of some form.
+ */
+function node_access_write_grants($node, $grants, $realm = NULL, $delete = TRUE) {
+  if ($delete) {
+    $query = 'DELETE FROM {node_access} WHERE nid = %d';
+    if ($realm) {
+      $query .= " AND realm in ('%s', 'all')";
+    }
+    db_query($query, $node->nid, $realm);
+  }
+
+  // This optimization reduces the number of db inserts a little bit. We could
+  // optimize further for mass updates if we wanted.
+  $values = array();
+
+  $query = '';
+  foreach ($grants as $grant) {
+    if ($realm && $realm != $grant['realm']) {
+      continue;
+    }
+    // Only write grants; denies are implicit.
+    if ($grant['grant_view'] || $grant['grant_update'] || $grant['grant_delete']) {
+      $query .= ($query ? ', ' : '') . "(%d, '%s', %d, %d, %d, %d)";
+
+      $values[] = $node->nid;
+      $values[] = $grant['realm'];
+      $values[] = $grant['gid'];
+      $values[] = $grant['grant_view'];
+      $values[] = $grant['grant_update'];
+      $values[] = $grant['grant_delete'];
+    }
+  }
+
+  $query = "INSERT INTO {node_access} (nid, realm, gid, grant_view, grant_update, grant_delete) VALUES " . $query;
+  
+  db_query($query, $values);
+}
+
+/**
+ * Implement a form that 
+ */
+function node_access_reset_page() {
+  $form['markup'] = array(
+    '#prefix' => '<p>',
+    '#value' => t('Here you may reset your node access database; this may be necessary right after installing or uninstalling a module that utilizes the node_access system.'),
+    '#suffix' => '</p>',
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Reset node access'),
+  );
+  return drupal_get_form('node_access_reset', $form);
+}
+
+/**
+ * reset the node access database
+ */
+function node_access_reset_submit() {
+  node_access_reset();
+  drupal_set_message(t('The node access tables have been reset.'));
+}
+
+function node_access_reset() {
+  db_query("DELETE FROM {node_access}");
+  $result = db_query("SELECT nid FROM {node}");
+  while ($node = db_fetch_object($result)) {
+    node_access_acquire_grants(node_load($node->nid));
+  }
+}
+/**
  * @} End of "defgroup node_access".
  */
 
