This is an add-on submodule to user_relationship. The idea is to allow site admins and individual users hide certain profile fields from those who are not in a relationship with them. Profile fields are not from the core profile.module but CCK nodes from content_profile.

This module is still a work in progress but implements most of this functionality. Would like someone trying it out and posting feedback on UI and features.

When creating/editing nodes designated as profile nodes, the module inserts controls for each field, to make the field private (i.e. not show to anyone but site admins), show to one or more relationship types (checkboxes), or keep it public to everyone.

Admins can set default visibility (to certain relationship types, or private) when configuring the CCK type. In that case the user cannot override their individual profile fields that were pre-set by admin.

Privacy works when looking at someone's profile, and when using search (core search) out of the box. It also works with Views, with a little tweaking.

  • For views shown as a table, no changes are needed.
  • For other display types (List, Unformatted) that use a Row Style, there is a row style plugin provided by the module called 'Profile Fields'. It applies privacy controls as the view is rendered. This is set in the Basic settings area of the view.

If the profile node is being shown on the registration form (http://drupal.org/node/260578, currently in a dev release of content_profile), privacy controls are not shown to keep it simple. This can be overridden with a config variable: add this to your settings.php $conf['user_relationships_field_perms_alter_registration_form'] = TRUE;

Outstanding issues:

  • Viewsthat use grouping: when grouping on a field that is subject to privacy controls, the node will still appear among other nodes grouped, even though its value is hidden. That's pretty serious, working to fix that.
  • Searching may bring up nodes where matching keywords are hidden, but displaying search results will not expose them.

Anyone using content_profile, it'd be great to test it on someone else's site.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

miraclestyle’s picture

Version: 6.x-1.0-beta7 » 6.x-1.0-beta9
Component: Code » User interface
Category: feature » bug
Priority: Normal » Critical

It seams that this module isn't working on beta9 version of User Relationships!
Elaboration:
After changing the visibility of a Content Profile node field (and saving the node), no matter of what options have been chosen, the field visibility setting defaults to "Show this field to: All Users", and the field remains visible indeed, to all users!

P.S. Apologies for any mistakes in Issue Settings, this is my first bug report. :D

alex.k’s picture

Component: User interface » Code
Assigned: Unassigned » alex.k
Category: bug » feature
Priority: Critical » Normal

Please wait a bit, there is a much updated version of this module that I'm finishing up, I will commit it for the next release if it passes testing.

advseb’s picture

subscribe

Liliplanet’s picture

super subscribe! thank you!

SocialNicheGuru’s picture

i will help test this. is there an official page for it?

how does this work with content privacy (the new cck field privacy)? Is it an either or relationship?

Chris

design.er’s picture

Alex, thanks a lot for this great feature! :)
I have the same bug as described in #1 and need this module for my current project, so I will help with testing and hope we'll get ready in/on time. ;)

Best Regards,
Stefan

SocialNicheGuru’s picture

how is this different from this module with this post

Integration of CCK_field_privacy with user_relationship_module

http://drupal.org/node/377950

alex.k’s picture

CCK Field Privacy provides privacy when viewing profile nodes. This module also provides privacy when using Views to display profiles, as well as when profiles are searched. The situation with CCK Field Privacy may have changed in the last few months, not sure.

I almost committed this module to UR for beta10 release, but it turns out it only supports views of type Node. If you build a view of type User or User Relationships (and use a relationship to pull in profile fields) privacy will not work. I'm attaching that version, which supersedes what was posted previously. With that caveat, it should work otherwise.

alex.k’s picture

Status: Active » Needs review
prdsp’s picture

This works well on regular core user profile pages with content profile enabled, however, when you apply the patch to content profile discussed here http://drupal.org/node/430220 which allows you to pull cck fields from content profile into panels 3, the fields that are supposed to be hidden are still visible. Is there any chance you might integrate this module with panels 3 and the patched version of content profile as this seems like its going to be the wave of the future when it comes to creating custom user profiles?

alex.k’s picture

Version: 6.x-1.0-beta9 » 6.x-1.x-dev

Sounds interesting. However, I have never written for Panels, and don't use them currently. Anything it does differently than node_view would have to be accounted for.

prdsp’s picture

Perhaps Merlin, Michelle and Fago could provide you with the assistance you need on this. If these 3 modules could work together it would be very powerful. I'm not a coder but I'm familiar with using all three modules and can provide assistance with testing.

prdsp’s picture

I've added a new feature request in the Panels 3 issue queue to have this module integrated with Panels. You can find the thread here http://drupal.org/node/466956

alex.k’s picture

Thanks, appreciate you following up.

Michelle’s picture

@alex: I don't know when I'll have time to look at this. If it helps to figure out why your code doesn't work with the CCK/Panels integration, here is the code that displays a field:

function content_content_field_content_type_render($subtype, $conf, $panel_args, $context) {
  if (is_array($context)) {
    $context = array_pop($context);
  }
  $node = isset($context->data) ? drupal_clone($context->data) : NULL;

  // Extract the node type and field name from the subtype
  list($node_type, $field_name) = explode(':', $subtype, 2);

  // Get the formatter that was selected in the settings dialog.
  $formatter = $conf['formatter'];

  // Get more information about our field.
  $field = content_fields($field_name);

  // Force panel settings into the field's display settings.
  $field['display_settings']['label']['format'] = $conf['label'] == 'normal' ? 'hidden' : $conf['label'];
  $field['display_settings']['full']['format'] = $formatter;
  $node->build_mode = NODE_BUILD_NORMAL;
  // TODO : allow panel-specific template suggestions for content-field.tpl.php ?

  $output = content_view_field($field, $node);

  $block->module = 'content';
  $block->delta = $field_name;
  if ($conf['label'] == 'normal') {
    $block->title = $field['widget']['label'];
  }
  $block->content = $output;

  return $block;
}

And this is to display an entire fieldgroup:

function fieldgroup_content_fieldgroup_content_type_render($subtype, $conf, $panel_args, $context) {
  $node = isset($context->data) ? drupal_clone($context->data) : NULL;
  $block = new stdClass();
  
  if ($node) {
    // Extract the node type and fieldgroup name from the subtype
    list($node_type, $fieldgroup_name) = explode(':', $subtype, 2);
  
    // Get a list of all fieldgroups for this node type
    $groups = fieldgroup_groups($node_type);

    if (isset($groups[$fieldgroup_name])) {
      $group = $groups[$fieldgroup_name];
      $output = array();

      foreach ($group['fields'] as $field_name => $field) {
        $field = content_fields($field_name, $node_type);
        $field_view = content_view_field($field, $node);
        if (!is_null($field_view)) {
          $output[] = $field_view;
        }
      }

      $block->title = $group['label'];
      $block->content = $output ? theme('fieldgroup_content_type', $output, $node->nid) : $conf['empty'];
    }
  }

  return $block;
}

Michelle

alex.k’s picture

Thanks, Michelle. I wonder if Panels works with content_permissions module. It implements the same kind of security, i.e. adding the #access flag during hook_nodeapi(op = 'view'). I modeled this module to the same behavior. If the view op is never called, then I think no access control modules would have a chance to mark up the fields.

Michelle’s picture

@alex: I haven't had a chance to dig into it but I think the key thing here may be that Panels isn't displaying the node; it's displaying the fields (or fieldgroups) directly.

Michelle

alex.k’s picture

Yup it's in general something that is easy to overlook when working with nodes... it's tempting to pull out fields knowing that the node as a whole is accessible - but if any modules try to apply access controls at the field level, the best practices are not so clear.

Michelle’s picture

Not a matter of being "tempting"; it's essential. It's the basis of the integration to be able to add individual fields and fieldgroups wherever you want on a panel. Overall node access can be taken care of at the context level but modules addressing things on the field level can't rely on those fields always being associated with the node. This will be even more important in D7 when fields can be added to anything.

Michelle

prdsp’s picture

FileSize
19.37 KB

I tried creating a content profile field view of type node and adding the view to the panel as a work around, however that didn't work either. I was thinking that since the view was of type node it might work but it doesn't

Michelle’s picture

@alex: I gave this some more thought while I was taking my son to school. Panels isn't the only issue here. Content Profile also provides the ability to display the fields anywhere. Any privacy module that relies on the fields being on the node in the normal manner isn't going to do it. It needs to be done at the field level. CCK already provides field viewing security but that's for the admin to set per role. It could serve as a model, though. If CCK doesn't provide the hooks needed to provide privacy directly, I suggest a patch to CCK do add in a hook for that. Then any module displaying CCK fields / fieldgroups would do it using the API that triggers hooks for other modules to deny access.

My apologies if any of this has been discussed. I was directed over here from the CP relationship issue and haven't been involved in this whole issue.

Michelle

alex.k’s picture

@prdsp in the view, use the "Profile fields" row style - this lets ur_field_perms do its work because the view is not a table view.

prdsp’s picture

Changing the row style didn't seem to have any effect. I am however able to get the entire content profile into panels with the UR field perms being fully functional.

This is done by adding a profile node relationship in the context tab...then when you go to add content to a region a new category will show up called node which should be right below miscellaneous...after clicking on the node category select node content...when the settings page appears uncheck "no extras" to make sure that your cck fields show up.

The only drawback to this is that you can't just only show certain fields...you have to show all of the content profile node. But the user is able to hide whatever fields they don't want to be seen. With the exception of the non-cck title, body & comment fields as it appears that the UR field perms module does not provide settings to hide the non-cck fields.

But the user does have the option to leave the body field blank & leave the comment field disabled. Or the administrator can get rid of the title by checking the override the title in the content settings when adding the content pane to a region in panels and leaving the override title blank. The administrator can also disable the body field when editting the content type by leaving the title of the body field blank...the admin can also leave comment disabled there as well. Doing all of this would leave you with just the cck fields which the user can hide or show as they please.

I am wondering though if it would be possible to add the views that are of type node to the new node category that appears when you add the profile node relationship in the context tab. Maybe having the views that I created above classified under the node category in panels instead of the views category would allow the ur field perms to work? I guess thats an answer that Michelle or Merlin would know more about.

dbeall’s picture

same issue w/profile fields in APK, but after getting it in I don't want to give it up.. it's a little over my head. interesting discussion, keeping an eye on this one..

alex.k’s picture

FWIW part of the reason this module doesn't offer options to hide non-CCK fields is I did not have any need to do that... The reason why is that it's possible to stick just to CCK for most if not all data in a user profile, unless you're doing something unusual. Consider:
* Title can, and should, be hidden using auto_nodetitle module, I set it automatically to be user's first and last name
* Node body - as you mentioned, it's hidden using standard node type options.
* Taxonomy - if you need to use this, use content_taxonomy, as it allows to tag nodes without saving the tags into the taxonomy system.
* Not sure there is anything else that comes to mind...
In any case, if the panel is showing a complete profile node then usual CCK "Display Fields" settings in content type setup should apply, i would think.

Michelle’s picture

In any case, if the panel is showing a complete profile node then usual CCK "Display Fields" settings in content type setup should apply, i would think.

It should, yes. The problem is that you generally won't want the panel to show the complete node but rather display fields and fieldgroups individually for better placement. And that's where depending on the whole node being there falls down.

Michelle

sumitk’s picture

Above module is not checking if a user has approved friend request of other user or not .. instead it is directly showing all profile fields checking rtids .... which is wrong as it should also check approved column of relationships table (set to 1 in approved case).

You can correct this by replacing this function in user_relationship_field.perms.module from line 356

/**
 * Check whether a field in a node is visible to a user
 *
 * @param $params array of parameters about the node: either array('node' => $node) if a complete node is available, 
 *        or array('nid' => $nid, 'type' => $node_type, 'uid' => $node_author) at a minimum.
 * @param $field_name field within the node to check
 * @param $uid optional, user account whose access to check, current user by default
 * @param $unknown_viewer if TRUE, only public fields are let through, i.e. viewer is not known at this time
 */
function _user_relationship_field_perms_allow_access($params, $field_name, &$viewer = NULL, $unknown_viewer = FALSE) {
  if (!$viewer->uid && !$unknown_viewer) {
    global $user;
    $viewer = $user;
  }
  //find out the node id and type
  if ($params['node']) {
    $nid = $params['node']->nid;
    $node_type = $params['node']->type;
    $node_author = $params['node']->uid;
  }
  else {
    if ($params['nid']) {
      $nid = $params['nid'];
    }
    if ($params['type'] && $params['uid']) {
      $node_type = $params['type'];
      $node_author = $params['uid'];
    } 
    else {//if only the nid is given, need to go through node_load()
      $node = node_load($nid);
      $node_type = $node->type;
      $node_author = $node->uid;
    }
  }
  //let node owner and privileged users see everything
  if (!$unknown_viewer && (user_access('disregard relationship field privacy', $viewer) || $node_author == $viewer->uid || $viewer->uid == 1)) {
    return TRUE;
  }
  //act only on types designated as profile types
  if (!is_content_profile($node_type)) {
    return TRUE;
  }
  //naive cache of the last node looked at during this request as usually this is called for every field in a single node
  static $current_nid, $current_type, $current_perms, $default_perms;
  if (!isset($current_nid) || $current_nid != $nid) {
    $current_nid = $nid;
    //load settings for this node
    $current_perms = _user_relationship_field_perms_load($nid);
  }
  if (!isset($current_type) || $current_type != $node_type) {
    //load default visibility settings for the content type
    $default_perms = _user_relationship_field_perm_defaults_load($node_type);
    $current_type = $node_type;
  }
  //now check if field is accessible
  //hide private field if the user is unknown
  if ($unknown_viewer) {
    return !$current_perms[$field_name] && !$default_perms[$field_name];
  }
  //now, hide if default is hidden
  if (is_array($default_perms[$field_name]) && $default_perms[$field_name][0] == 'noone') {
    return FALSE;
  }
  //hide if default is public but user has set to hidden
  if (!is_array($default_perms[$field_name]) && $current_perms[$field_name] == 'noone') {
    return FALSE;
  }
  //hide if defaults specify relations but viewer is not in any of them, or if default is public but author
  //has specified relations and viewer is not in any of them
  if (is_array($default_perms[$field_name]) || (
           !is_array($default_perms[$field_name]) && is_array($current_perms[$field_name]))) {//xor anyone?
    //intersect rtids from permissions with rtids of node author to viewer
    static $rtids;
    static $approved;
    if (!isset($rtids[$nid][$viewer->uid])) {//naive cache of relationships between $uid and node author, remembers last used $uid and node
      $rtids = array($nid => array($viewer->uid => array_keys(user_relationships_load(array("between" => array($node_author, $viewer->uid)), array("sort" => "rtid")))));
      $approved =  array_keys(user_relationships_load(array("between" => array($node_author, $viewer->uid)), array("sort" => "approved")));
    }
    //do not use user's settings if defaults are on, to allow changing defaults on existing nodes
    //checking if other user has approved the relationship or not
    if ($approved[0] == 1) {
      $active_rtids = is_array($default_perms[$field_name]) ? $default_perms[$field_name] : $current_perms[$field_name];
      return is_array($active_rtids) && count(array_intersect($rtids[$nid][$viewer->uid], $active_rtids)) > 0;
    } else {
      return FALSE;
    }
  }
  return TRUE;
}

Modified module is in attachment.

sumitk’s picture

Above code is fetching approved variable in $approved array as

$approved =  array_keys(user_relationships_load(array("between" => array($node_author, $viewer->uid)), array("sort" => "approved")));

and testing a condition if it is 1 OR not.

chaosprinz’s picture

Hello,
i dont know if it can help ya guy with your real cool work. I enabled the submodule from #29 and got these 2 messages directly after turning on the module:

* warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\includes\common.inc on line 3297.
* warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\includes\common.inc on line 3218.

Let me me know if you need more infomation and what kind of information.

SocialNicheGuru’s picture

can I have your advise.

I am unsure about which way to go

do i use cck field permissions + ur
http://drupal.org/node/377950

or ur field perms module.

I have read this thread and the one I posted and I would love your advise on which solution.

thanks,
Chris

yajnin’s picture

subscribe

Jehu’s picture

Category: feature » support
FileSize
2.6 KB

In my view the contents are always shown no matter the field privacy settings. Please take look at the view i've attached.

okday’s picture

Why not including this sub-module in the user relationship suite?

okday’s picture

My hidden fields are always shoen too.

Please update this module.

brunorios1’s picture

subscribing...

mrf’s picture

Assigned: alex.k » Unassigned
Category: support » feature
mrf’s picture

Status: Needs review » Postponed

Don't see this getting added to 6.xt, and this would end up being a very different module for 7.x.

That being said I think its a very useful, and it would be great if someone takes what is here and fixes the remaining bugs.