From 9658a3397733ece941bb00eafb534754ed2f47ab Mon Sep 17 00:00:00 2001
From: Peter <aegir@localhost.com>
Date: Tue, 14 Sep 2010 12:33:40 -0500
Subject: [PATCH] Combined commits for patch

now works with a private field, can disable a field, separate checkbox for checking with content profiles, ability to set fields NAAR will pass through even when set to private, and untested referse checking per field
started work on disabling naar on certain field instances

working with ability to disable certain fields and use a private cck field

now works with a private field, can disable a field, separate checkbox for checking with content profiles, ability to set fields NAAR will pass through even when set to private, and untested referse checking per field

added comments
---
 nodeaccess_autoreference.admin.inc |   25 +++++++-
 nodeaccess_autoreference.inc       |  120 ++++++++++++++++++++++++++++++++----
 nodeaccess_autoreference.module    |  114 ++++++++++++++++++++++++++++++++++
 3 files changed, 245 insertions(+), 14 deletions(-)

diff --git a/nodeaccess_autoreference.admin.inc b/nodeaccess_autoreference.admin.inc
index 9a1d32f..06c9b8b 100644
--- a/nodeaccess_autoreference.admin.inc
+++ b/nodeaccess_autoreference.admin.inc
@@ -38,19 +38,40 @@ function nodeaccess_autoreference_admin_form() {
     '#description' => t('Select if you want to enable checking permissions through owners. Especially when you have references to user node profiles.'),
     '#default_value' => variable_get('nodeaccess_autoreference_via_owner', TRUE),
   );
+  //Allows you to check per content profile.  This is usually done with "via owner" but sometimes you just want to check per content profile and not via owner on all nodes.
+  $form['nodeaccess_autoreference']['nodeaccess_autoreference_via_content_profile'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Check permission via content profile.'),
+    '#description' => t('Select if you want to enable checking permissions through content profile.'),
+    '#default_value' => variable_get('nodeaccess_autoreference_via_content_profile', TRUE),
+  );
 
   $form['nodeaccess_autoreference']['nodeaccess_autoreference_rebuild'] = array(
     '#type' => 'submit',
     '#value' => t('Rebuild permissions'),
     '#submit' => array('nodeaccess_autoreference_rebuild_submit'),
-  ); 
+  );
+  //Allows you to enter the fields that NAAR will go threw even if the node is set to "private"
+  $form['nodeaccess_autoreference_private'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('"Private" Settings'),
+    '#description' => t('Enter in the fields you want to allow NAAR to pass through on "private" nodes.  This only works for nodereference fields.'),
+    '#collapsible' => TRUE,
+  );
+  $form['nodeaccess_autoreference_private']['nodeaccess_autoreference_private'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Private Fields'),
+    '#description' => t('Even if nodes are marked as private, NAAR will still pass through and check access through these fields. <br/> enter fields separated by a space.  Example:field_project field_clients'),
+    '#default_value' => variable_get('nodeaccess_autoreference_private', t('')),
+  );
 
   $form['nodeaccess_autoreference_adv'] = array(
     '#type' => 'fieldset',
     '#title' => t('Advanced Settings'),
     '#description' => t('Change this settings if you really know what you are doing. You could loss your website performance or even have some crashes.'),
     '#collapsible' => TRUE,
-  ); 
+  );
+
 
   $form['nodeaccess_autoreference_adv']['nodeaccess_autoreference_reverse_reference'] = array(
     '#type' => 'checkbox',
diff --git a/nodeaccess_autoreference.inc b/nodeaccess_autoreference.inc
index 2f03184..d0bd2e1 100644
--- a/nodeaccess_autoreference.inc
+++ b/nodeaccess_autoreference.inc
@@ -62,6 +62,7 @@ function nodeaccess_autoreference_find_connection($node, $obj = NULL) {
     . t('Connected: %connected; Path between user %uid and node %nid (%type): %path',
     array('%nid' => $node->nid, '%uid' => $obj->uid, '%type' => $node->type, '%path' => !empty($path) ? print_r($path,true) : t('n/a'), '%connected' => ($path ? 'YES' : 'NO'))), 'status');
   }
+
   return $res;
 }
 
@@ -76,11 +77,13 @@ function nodeaccess_autoreference_find_connection($node, $obj = NULL) {
  *   array of path passed by referenced (should be empty on first call)
  * @param integer $depth optional
  *   optional parameter for depth checking
+ * @param text $private optional
+ *   optional parameter for setting a node as "private" (ie no naar checking)
  * @return matches
  *   returns all matches where connection has been found
  *
  */
-function nodeaccess_autoreference_obj_connected($obj, $user, &$path = array(), &$ignore_list = array(), $depth = 0) {
+function nodeaccess_autoreference_obj_connected($obj, $user, &$path = array(), &$ignore_list = array(), $depth = 0, &$private = 'no') {
   if ($depth == 0) {
     $obj_id = ($obj->nid ? $obj->nid : $obj->uid);
     $path[] = "$obj->type|$type|" . $obj_id; // init path
@@ -94,11 +97,10 @@ function nodeaccess_autoreference_obj_connected($obj, $user, &$path = array(), &
     return TRUE;
   }
 
-  $refs = nodeaccess_autoreference_obj_references($obj, variable_get('nodeaccess_autoreference_reverse_reference', FALSE));
+  $refs = nodeaccess_autoreference_obj_references($obj, variable_get('nodeaccess_autoreference_reverse_reference', FALSE), $private);
   foreach ($refs as $field_name => $ref) {
     global $na_skip_next_load;
     $na_skip_next_load = TRUE;
-
     $n_obj = NULL;
     if (isset($ref['nid'])) {
       $n_obj = node_load(array('nid' => $ref['nid']));
@@ -111,6 +113,7 @@ function nodeaccess_autoreference_obj_connected($obj, $user, &$path = array(), &
     }
     if (nodeaccess_autoreference_same_objs($user, $n_obj)) {
       $path[] = $field_name;
+
       return TRUE;
     } else if (!array_key_exists($ref['nid'], $ignore_list)) {
       if (variable_get('nodeaccess_autoreference_debug_more', FALSE)) {
@@ -125,7 +128,7 @@ function nodeaccess_autoreference_obj_connected($obj, $user, &$path = array(), &
         }
         $ret = $data;
       } else {
-        $ret = nodeaccess_autoreference_obj_connected($n_obj, $user, $path, $ignore_list, $depth+1);
+        $ret = nodeaccess_autoreference_obj_connected($n_obj, $user, $path, $ignore_list, $depth+1, $private);
       }
     }
     if ($ret) {
@@ -159,18 +162,26 @@ function nodeaccess_autoreference_same_objs($a, $b) {
  *   could be user or node object
  * @return matches
  *   returns all matches where connection has been found
+ * @param text $private optional
+ *   optional parameter for setting a node as "private" (ie no naar checking)
  *
  */
-function nodeaccess_autoreference_obj_references($obj, $reverse = FALSE) { // data = user/node
+function nodeaccess_autoreference_obj_references($obj, $reverse = FALSE, &$private = 'no') { // data = user/node
   $matches = array();
   $type = $obj->nid ? 'nid' : 'uid';
   $id = $type == 'nid' ? $obj->nid : $obj->uid;
-
   if (is_array($obj) || is_object($obj)) {
     foreach ($obj as $field_name => $value) {
       if (is_array($value) || is_object($value)) {
-        foreach ($value as $key2 => $value2) {  
+        foreach ($value as $key2 => $value2) {
         if (is_array($value2)) {
+          if (!empty($value2['value']) && $field_info = content_fields($field_name)) {
+            //dsm(variable_get('naar_private_'.  $obj->type, 0));
+              $privatefield = variable_get('naar_private_'.  $obj->type, 0);
+              if ($field_info['type'] == 'text' && $privatefield[$obj->type][$field_name] == 1 && array_key_exists($field_name, $privatefield[$obj->type])) { /* support for private naar nodes */
+                $private = 'yes';
+              }
+            }
             if (!empty($value2['uid']) && $field_info = content_fields($field_name)) {
               if ($field_info['type'] == 'userreference') { /* support for userreference module */
                 $uid = $value2['uid'];
@@ -178,8 +189,20 @@ function nodeaccess_autoreference_obj_references($obj, $reverse = FALSE) { // da
               }
             } else if (!empty($value2['nid']) && $field_info = content_fields($field_name)) {
               if ($field_info['type'] == 'nodereference') { /* support for nodereference module */
-                $nid = $value2['nid'];
-                $matches["$type:$id|$obj->type|$field_name|nid:$nid"]['nid'] = $nid;
+                if(variable_get('naar_disable_'. $obj->type . '_'.$field_info['field_name'], FALSE) != TRUE) {
+		  //if(in_array($field_info['field_name'],explode(' ', nodeaccess_autoreference_allowed()))){
+                    if ($private == 'yes') {
+                      $allowed_fields = explode(' ', variable_get('nodeaccess_autoreference_private', ''));
+                      if (in_array($field_name,$allowed_fields)){
+			$nid = $value2['nid'];
+			$matches["$type:$id|$obj->type|$field_name|nid:$nid"]['nid'] = $nid;
+		      }
+                    }
+		    else {
+                     $nid = $value2['nid'];
+                     $matches["$type:$id|$obj->type|$field_name|nid:$nid"]['nid'] = $nid;	
+		    }
+                }
               }
             }
           }
@@ -189,8 +212,19 @@ function nodeaccess_autoreference_obj_references($obj, $reverse = FALSE) { // da
     if (variable_get('nodeaccess_autoreference_via_owner', TRUE)) {
       $type == 'nid' ? $matches["uid:$obj->uid|via_owner|$type:$obj->nid:$obj->type"]['uid'] = $obj->uid : NULL;
     }
+    if (variable_get('nodeaccess_autoreference_via_content_profile', TRUE) && module_exists('content_profile')) {
+      $ptypes = content_profile_get_types();
+      foreach ($ptypes as $key => $pnode) {
+	if ($obj->type == $key) {
+	  $ptype = 1; 
+	}
+      }
+      if ($type == 'nid' && isset($ptype) && $ptype == 1){
+	$matches["uid:$obj->uid|via_content_profile|$type:$obj->nid:$obj->type"]['uid'] = $obj->uid;
+      } 
+    }
     /* FIXME: multi-fields per one content are currently not supported */
-    if ($reverse) {
+    if ($reverse || variable_get('naar_reverse_'.  $obj->type . '_'.$field_info['field_name'], FALSE)) {
       /* find which content type can be referenced to current type */
       $ct_type = $obj->type; // current content type name
       $fields = content_fields(); // get info about all fields
@@ -251,7 +285,6 @@ function nodeaccess_autoreference_obj_references($obj, $reverse = FALSE) { // da
       }
     }
   }
-
   return $matches;
 }
 
@@ -284,7 +317,8 @@ function nodeaccess_autoreference_node_get_grants($node, $user = NULL) {
       'grant_delete' => user_access("delete referenced $node->type content"),
     );
     return $grants;
-  } else {
+  }
+  else {
     return NULL;
   }
 }
@@ -305,4 +339,66 @@ function nodeaccess_autoreference_node_write_grants($node, $grants) {
     $msg = 'Added permissions to node %nid. (permission: %permission)';
   }
 }
+/*
+ * Function added for the "hack" in .module (in nodeapi) that looks for the referencing nodes
+ * $obj is just the $node object.
+ */
+function nodeaccess_autoreference_reverse_check ($obj) {
+$type = 'nid';
+      /* find which content type can be referenced to current type */
+      $ct_type = $obj->type; // current content type name
+      $fields = content_fields(); // get info about all fields
+      $referenced_type = array(); // init variable
+      $referenced_roles = array(); // init variable
+      foreach ($fields as $field_name => $field_data) {
+        if ($field_data['type'] == 'nodereference' && $type == 'nid') { // consider only referenced fields
+          /* get the node types which could be referenced to current node */
+          $referenced_types = $field_data['referenceable_types'] ? drupal_map_assoc($field_data['referenceable_types']) : array(); // select types which can be referenced
+          if (in_array($ct_type, $referenced_types)) {
+            $referenced_type[$field_data['type_name']] = $ct_type; // set which types could be referenced to current type
+            $field_names[$field_name] = $field_data['type'];
+          }
+        } 
+      }
+      /* get all possible nids which could referencing to that type */
+      if (!empty($referenced_type)) {
+        $nid = $obj->nid; // current node id
+        $ct_type = $obj->type; // current content type name
+        $ref_types = implode("', '", array_keys($referenced_type));
+        $result = db_query("SELECT nid FROM {node} WHERE type IN ('$ref_types') AND nid != $nid");
+        while ($row = db_fetch_object($result)) {
+          if ($node = node_load($row->nid)) {
+            foreach ($field_names as $field_name_ok => $field_data) {
+              if (property_exists($node, $field_name_ok)) {
+                foreach ($node->{$field_name_ok} as $key => $id_obj) {
+                  if ($id_obj['nid'] == $nid) {
+                    $matches2["nid:$nid:$type|rev_nid:$field_name_ok|nid:$node->nid"]['nid'] = $node->nid;
+                  }
+                }
+              }
+            }
+          }
+        } // end: while
+      }
+
+      if (!empty($referenced_roles)) {
+        $uid = $id; // current user id
+        $ref_types = implode(", ", array_keys($referenced_roles));
+        $result = db_query("SELECT nid FROM {node} WHERE type IN ('$ref_types')");
+        while ($row = db_fetch_object($result)) {
+          if ($row = node_load($row->nid)) {
+            foreach ($field_names_user as $field_name_ok => $field_data) {
+              if (property_exists($row, $field_name_ok)) {
+                foreach ($row->{$field_name_ok} as $key => $id_obj) {
+                  if ($id_obj['uid'] == $id) {
+                    $matches2["uid:$id|rev_uid:$field_name_ok|nid:$row->nid:$row->type"]['nid'] = $row->nid;
+                  }
+                }
+              }
+            }
+          }
+        } // end: while
+      }
+    return $matches2;
 
+}
diff --git a/nodeaccess_autoreference.module b/nodeaccess_autoreference.module
index dadaa0e..01f71d7 100644
--- a/nodeaccess_autoreference.module
+++ b/nodeaccess_autoreference.module
@@ -153,7 +153,27 @@ function nodeaccess_autoreference_nodeapi(&$node, $op) {
       module_load_include('inc', 'nodeaccess_autoreference'); // load additional function from included file
       nodeaccess_autoreference_find_connection($node);
     }
+
   }
+  if ($op == 'update'){
+    //grab the nid's that are referencing the current node
+    //Delete NAAR node access to those referencing nodes so "reset" them.
+    //this may be a hack and needs changed.
+    $reverse = nodeaccess_autoreference_reverse_check($node);
+    $query = 'DELETE FROM {node_access} WHERE nid = %d';
+    $query .= " AND realm in ('%s', 'all')";
+    //$realm1 = 'content_access_rid';
+    $realm = 'nodeaccess_autoreference_owner';
+    if (isset($reverse)) {
+      foreach ($reverse as $pointer => $nid1) {
+	//remove the access from nodes referencing the current node for all users
+	db_query($query, $nid1['nid'], $realm);
+	//db_query($query, $nid1['nid'], $realm1);
+
+      }
+    }
+  }
+
 } 
 
 /**
@@ -163,7 +183,101 @@ function nodeaccess_autoreference_node_access_records($node) {
   if (variable_get('nodeaccess_autoreference_disable', FALSE)) {
     return;
   }
+
   module_load_include('inc', 'nodeaccess_autoreference'); // load additional function from included file
   return nodeaccess_autoreference_node_get_grants($node);
 }
 
+/**
+ * Implementation of hook_form_FORM_ID_alter().
+ * This adds some options to the cck field settings
+ * Allows you to disable naar on a per field basis
+ * Allows you to make a "text" field a private checkbox so as to disable NAAR on a per node basis
+ * UNTESTED - Allows you to turn on reverse reference checking on a per field basis
+ */
+function nodeaccess_autoreference_form_content_field_edit_form_alter(&$form, $form_state) {
+
+  // See if this is a FileField.
+  if( $form["#field"]["type"] == "nodereference" ) {
+      // Create Node access auto reference fieldset for node reference fields.
+      $form['nodeaccess_autoreference_nodereference'] = array(
+        "#type" => "fieldset",
+        "#weight" => -1,
+        "#title" => t('Node Access Auto-reference'),
+      );
+
+      $form['nodeaccess_autoreference_nodereference']['naar_disabled'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Disable Nodereference Autoreference access checking for this field?'),
+        '#default_value' => variable_get('naar_disable_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name'], FALSE),
+      );
+      $form['nodeaccess_autoreference_nodereference']['naar_reverse'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Enable reverse references checking.'),
+        '#description' => t('Give permission to parent nodes which have no references it-self, but other nodes referencing to it.'),
+        '#default_value' => variable_get('naar_reverse_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name'], FALSE),
+      );
+      $form['#submit'][] = 'nodeaccess_autoreference_nodereference_submit';
+  }
+  if( $form["#field"]["type"] == "text" ) {
+      // Create Node access auto reference fieldset for node reference fields.
+      $form['nodeaccess_autoreference_text'] = array(
+        "#type" => "fieldset",
+        "#weight" => -1,
+        "#title" => t('Node Access Auto-reference PRIVATE settings'),
+      );
+      $privatefield= variable_get('naar_private_'.  $form['#field']['type_name'], 0);
+      $field_type = $form['#field']['type_name'];
+      $field_name = $form['#field']['field_name'];
+      $form['nodeaccess_autoreference_text']['naar_private'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('To make this a node set as private from node access autoreference?'),
+        '#description' => t('(NOTE: private only works for node reference fields) For NAAR to ignore this content type, the of this field value must be set to "yes".  <br/>For example, if your using a "select list" text widget your OPTIONS would be something like:<br/>no|No<br/>yes|Yes'),
+        '#default_value' => $privatefield != 0 ? $privatefield[$field_type][$field_name] : 0,
+      );
+      $form['#submit'][] = 'nodeaccess_autoreference_text_submit';
+
+  }
+
+}
+/*
+ * Submit handler for the nodereference field options
+ */
+function nodeaccess_autoreference_nodereference_submit( $form, &$form_state ) {
+  //setting and deleting of disabled settings
+  if ($form_state['values']['naar_disabled'] == 1) {
+    variable_set('naar_disable_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name'], FALSE);
+  }
+  else {
+    variable_del('naar_disable_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name']);
+  //setting and deleting of Reverse settings
+  }
+  if ($form_state['values']['naar_reverse'] == 1) {
+    variable_set('naar_reverse_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name'], FALSE);
+  }
+  else {
+    variable_del('naar_reverse_'.  $form['#field']['type_name']. '_' . $form['#field']['field_name']);
+  }
+
+  }
+/*
+ * Submit handler for the text field options
+ */
+function nodeaccess_autoreference_text_submit( $form, &$form_state ) {
+
+  if ($form_state['values']['naar_private'] == 1) {
+    $privatefield = array(
+        $form['#field']['type_name'] => array(
+            $form['#field']['field_name'] => 1
+        ),
+    );
+    variable_set('naar_private_'.  $form['#field']['type_name'], $privatefield);
+  }
+  else {
+    $field = array(
+        $form['#field']['type_name'] => array(
+            $form['#field']['field_name'] => 0
+        ),
+    );
+    variable_set('naar_private_'.  $form['#field']['type_name'], $privatefield);  }
+}
\ No newline at end of file
-- 
1.7.0.4

