Index: cck_field_privacy.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck_field_privacy/cck_field_privacy.module,v
retrieving revision 1.3.2.2.2.10
diff -u -r1.3.2.2.2.10 cck_field_privacy.module
--- cck_field_privacy.module	21 Mar 2009 20:46:15 -0000	1.3.2.2.2.10
+++ cck_field_privacy.module	10 May 2009 21:08:53 -0000
@@ -422,4 +422,104 @@
   }
   variable_set('cckfp_values', serialize($stored_values));
   drupal_set_message('Settings Changed.');
-}
\ No newline at end of file
+}
+
+/**
+ * Implementation of hook_views - all views code in cck_field_privacy.module
+ */
+function cck_field_privacy_views_api() {
+  return array(
+    'api' => 2,
+  );
+}
+
+/**
+ * get the names of all inaccessible fields for a given user/node
+ * return array of field names that are inaccessible for given node or TRUE/FALSE if user is specified
+ */
+function _cck_get_inaccessible_fields($user, $node, $field = NULL) {
+  static $cached_results = array();
+  // check node type
+  $active_fields = _cck_field_privacy_get_active_fields($node->type);
+  
+  // do expensive db check only if it's a privacy controlled field (and if field is specified only if the field requested is privacy controlled)
+  if (!empty($active_fields) && (is_null($field) || array_key_exists($field, $active_fields)) && $user->uid != $node->uid) {
+    $cached_result = $cached_results[$node->uid][$node->type];
+    
+    if (isset($cached_result)) {
+      return is_null($field) ? $cached_result : isset($cached_result[$field]);
+    }
+    
+    $result = db_query("SELECT field_name, permission FROM {cckfp} WHERE uid = %d AND type_name = '%s' ORDER BY field_name DESC", $node->uid, $node->type);
+    
+    if ($result) {
+      while ($permissions = db_fetch_object($result)) {
+        if ($permissions->permission == 'e') {
+          continue;
+        } 
+        else if ($permissions->permission == 'n') {
+          $inaccessible_fields[$permissions->field_name] = $permissions->field_name;
+        } 
+        else if (!empty($permissions->permission)) {
+          $node_user = user_load(array('uid' => $node->uid));
+          $plugin_access_result = module_invoke($permissions->permission, 'cck_field_privacy_access', $node_user, $user);
+          //Uncomment the next line to enable debug output to the watchdog when testing views access
+          //watchdog('cckfp', 'result of module '.$permissions->permission.' check: '.print_r($plugin_access_result, TRUE));
+          if ($plugin_access_result === FALSE) {
+            $inaccessible_fields[$permissions->field_name] = $permissions->field_name;
+          }
+        }
+      }
+    }   
+    
+    $cached_results[$node->uid][$node->type] = $inaccessible_fields;
+    
+    return is_null($field) ? $inaccessible_fields : isset($inaccessible_fields[$field]);
+  }
+}
+
+/**
+ * for a given content type - get the active fields
+ * if not content type given gets all active fields
+ */
+function _cck_field_privacy_get_active_fields($type = NULL) {
+  static $cached_all_active_fields;
+  static $cached_active_fields_by_type = array();
+  
+  if (is_null($type)) {
+    if (isset($cached_all_active_fields)) {
+      return $cached_all_active_fields;
+    }
+  } 
+  else {
+    if (isset($cached_active_fields_by_type[$type])) {
+      return $cached_active_fields_by_type[$type];
+    }
+  }
+  
+  $types = variable_get('cckfp_types', NULL);
+  $active_fields = array();
+
+  $values = unserialize(variable_get('cckfp_values', array()));
+
+  // if (array_key_exists($type, $types) && $types[$type] != '0') {
+  foreach ($types as $key => $value) {
+    // if no type specified or the type matches and is not '0' - add the field names to the list of active fields
+    if ((is_null($type) || $key == $type) && $value != '0') {
+      foreach ($values[$key] as $field_name => $enabled) {
+        if (!strpos($field_name, '_default') && $enabled == TRUE) {
+          $active_fields[$field_name] = $field_name;
+        }
+      }
+    }
+  }
+  
+  if (is_null($type)) {
+    $cached_all_active_fields = $active_fields;
+  } 
+  else {
+    $cached_active_fields_by_type[$type] = $active_fields;
+  }
+  
+  return $active_fields;
+}
--- cck_field_privacy.views.inc
+++ cck_field_privacy.views.inc
@@ -0,0 +1,108 @@
+<?php
+// $Id$
+/**
+ * Apply cck field privacy to Views 2
+ */
+
+/**
+ * Implementation of hook_views_pre_render - decorates the views cck field handlers
+ */
+function cck_field_privacy_views_pre_render(&$view) {
+  foreach ($view->field as $field_handler_name => &$field_handler) {
+    if (is_subclass_of($field_handler, 'content_handler_field')) {
+      // check if this field is cckfp enabled - only decorate cckfp enabled fields
+      $active_fields = _cck_field_privacy_get_active_fields();
+      
+      // get the field name
+      $field_name = $field_handler->definition['content_field_name'];
+      
+      if (isset($active_fields[$field_name])) {
+        $cckfp_handler = new cckFieldPrivacyViewsFieldHandler($field_handler);
+        $view->field[$field_handler_name] = $cckfp_handler;
+      }
+    }
+  }
+}
+
+/**
+ * Decorator for views cck field handler - content_handler_field - to control access to cckfp enabled fields
+ * @todo improve performance - this approach runs through the result set for each cck field in the view
+ */
+class cckFieldPrivacyViewsFieldHandler {
+    var $handler;
+    
+    /**
+     * constructor - saves reference to the decorated handler object
+     */
+    function __construct( content_handler_field $handler ) {
+        $this->handler =& $handler;
+    }
+        
+    /**
+     * implement pre_render decorator to check field access and strip field data from results if access is not granted
+     */
+    function pre_render($values) {
+      global $user;
+      
+      if (isset($this->handler->definition['content_field_name'])) {
+        // the cck field name
+        $cck_field_name = $this->handler->definition['content_field_name'];
+                
+        foreach ($values as $key => $value) {
+          $node = node_load($value->nid);
+          
+          // check if this instance of field is inaccessible to the current user
+          $inaccessible = _cck_get_inaccessible_fields($user, $node, $cck_field_name);
+          
+          if ($inaccessible === TRUE) {
+            //Uncomment the next line to enable debug output into the watchdog for testing if the cckfp module is blocking fields correctly.
+            //watchdog('cckfp', 'user '. $user->name .', should not see the '. $cck_field_name .' for node '. $node->title .' which belongs to '. $node->uid);
+            // not accessible - remove all data associated with this field
+            if (!$this->handler->defer_query) {
+              // remove the actual data if the data has already been loaded by the query - i.e. not defer_query
+              unset($values[$key]->{$this->handler->field_alias});                            
+            } 
+            else {
+              // data has not already been loaded by the query
+              // remove the data that the handler uses to build the field
+              // clone because the data may be shared with other handlers whose field in this row is accessible
+              $values[$key] = clone $values[$key];
+              unset($values[$key]->{$this->handler->field_alias});              
+            }
+          }
+        }
+      }
+            
+      // pass on call to decorated handlers own pre_render method
+      if ( method_exists( $this->handler, 'pre_render' )) {
+        return call_user_func_array( array( $this->handler, 'pre_render' ), array($values) );
+      }
+    }
+    
+    /**
+     * pass through gets to decorated object
+     */
+    function __get( $var ) {
+        if ( isset( $this->handler->$var )) {
+            return $this->handler->$var;
+        }
+        return FALSE;
+    }
+    
+    /**
+     * pass through sets to decorated object
+     */
+    function __set( $var, $val ) {
+        $this->handler->$var = $val;
+    }
+    
+    /**
+     * pass through all method calls that aren't implemented by this decorator
+     */
+    function __call( $method, $arguments ) {
+        if ( method_exists( $this->handler, $method )) {
+          return call_user_func_array( array( $this->handler, $method ), $arguments );
+        }
+        return FALSE;
+    }
+}


