CiviCRM Community Forums (archive)

*

News:

Have a question about CiviCRM?
Get it answered quickly at the new
CiviCRM Stack Exchange Q+A site

This forum was archived on 25 November 2017. Learn more.
How to get involved.
What to do if you think you've found a bug.



  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Help with ACL using Hooks
Pages: [1]

Author Topic: Help with ACL using Hooks  (Read 1573 times)

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Help with ACL using Hooks
August 12, 2011, 08:32:42 am
I'm trying to implement ACL using hooks as per:
http://wiki.civicrm.org/confluence/display/CRMDOC40/CiviCRM+hook+specification#CiviCRMhookspecification-Permissionrelatedhooks

which stemmed from this discussion:
http://forum.civicrm.org/index.php/topic,3695.msg50469.html#msg50469

I'm new to hooks so bear with me. Firstly, the two examples shown both are based on the assumption that the custom field names in both custom field sets being the same (in this case - branch, electorate and province). As far as I can tell in the current version of civicrm this isn't possible as all custom field names must be unique (or at least that is what I get told when I try to enter one that is the same!)

So that requires some changes to the example use of the hook, but I think that is pretty straightforward to do. Just define to custom field arrays and move back and forth between them.

The bigger problem I am having is that the example defines $regionTable at the beginning but then seems to start using regionTable instead of $regionTable as the table name. There is no regionTable in the civicrm database so am I misunderstanding something here.:
Code: [Select]
$tables[$regionTable] = $whereTables[$regionTable] =
        "LEFT JOIN {$regionTable} regionTable ON contact_a.id = regionTable.entity_id"

I also don't understand what contact_a.id refers to since again, there is no contact_a table in the civicrm database.

So I'm a little confused. Trying to work through this but if anyone has any advice that would be awesome.

Brian

For the sake of completeness here is my current hook - which I believe allows for the different custom field names I mentioned.
Code: [Select]
<?php

function newacl_civicrm_aclWhereClause( $type, &$tables, &$whereTables, &$contactID, &$where ) {

if ( ! 
$contactID ) {
        return;
    }

    
$permissionTable = 'civicrm_value_permissions_2';
    
$additionalInfoTable = 'civicrm_value_additional_individual_informatio_1';
    
$permissionFields = array( 'provincial_riding_9' => 'Integer',
                               
'commission_10'   => 'Integer');

$additionalInfoFields = array( 'official_provincial_riding_2' => 'Integer',
                            
   'commissions_8'   => 'Integer');

$additionalInfoFieldNames = array( 'official_provincial_riding_2','commissions_8');   
  
    
// get all the values from the permission table for this contact
    
$keys = implode( ', ', array_keys( $permissionFields ) );
$sql = "
SELECT 
$keys
FROM   
{$permissionTable}
WHERE  entity_id = 
$contactID
"
;

    
$dao = CRM_Core_DAO::executeQuery( $sql,
                                       
CRM_Core_DAO::$_nullArray );
   
    if ( ! 
$dao->fetch( ) ) {
        return;
    }

    
$tables[$additionalInfoTable] = $whereTables[$additionalInfoTable] =
        
"LEFT JOIN {$additionalInfoTable} additionalInfoTable ON contact_a.id = additionalInfoTable.entity_id";

    
$clauses = array( );
    foreach( 
$permissionFields as $field => $fieldType ) {
        
$i = 0;
if ( ! empty( $dao->$field ) ) {
if ( strpos( CRM_Core_DAO::VALUE_SEPARATOR, $dao->$field ) !== false ) {
                
$value = substr( $dao->$field, 1, -1 );
                
$values = explode( CRM_Core_DAO::VALUE_SEPARATOR, $value );
                foreach ( 
$values as $v ) {
$fieldName = $additionalInfoFieldNames[$i];
                    
$clauses[] = "additionalInfoTable.{$fieldName} = $v";
                }
            } else {
               
if ( $fieldType == 'String' ) {
                    
$fieldName = $additionalInfoFieldNames[$i];
$clauses[] = "additionalInfoTable.{$fieldName} = '{$dao->$field}'";
                } else {
$fieldName = $additionalInfoFieldNames[$i];
$clauses[] = "additionalInfoTable.{$fieldName} = {$dao->$field}";
}
            }
        }
$i++;
}

    if ( ! empty( 
$clauses ) ) {
        
$where .= ' AND (' . implode( ' OR ', $clauses ) . ')';
    }
}
?>



« Last Edit: August 12, 2011, 08:42:10 am by bpmccain »

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 12, 2011, 02:26:02 pm
Ok, I have spent all day on this and tracked the problem down to one very small, very strange piece of behaviour (at least IMO after 5 hours of looking at this).

If we look at these lines of code in isolation,
Code: [Select]
$clauses[] = "groupTable.{$groupFields[$i]} = {$dao->$field}";
if ( ! empty( $clauses ) ) {
        $where .= ' AND '.implode( ' OR ', $clauses ).'';
}
echo $where;

I get the following output and the ACL permissioning DOESN'T work (DB Error: Syntax Error)
Code: [Select]
( ( `civicrm_group_contact_cache_3`.group_id = 3 ) ) AND groupTable.official_provincial_riding_2 =  44

If instead, I change my code to
Code: [Select]
$clauses[] = "groupTable.{$groupFields[$i]} = 44";
if ( ! empty( $clauses ) ) {
        $where .= ' AND '.implode( ' OR ', $clauses ).'';
}
echo $where;

I get the following output and the ACL permissioning DOES work:
Code: [Select]
( ( `civicrm_group_contact_cache_3`.group_id = 3 ) ) AND groupTable.official_provincial_riding_2 = 44
The only difference between the two $where statements is an extra space between the = and the 44. In fact I could only see the extra space when I copied and pasted it to a text editor, it didn't actually show up in the browser.

So the question is, why {$dao->$field} which is equal to 44 in this case, different from the actual number 44, and why does it cause the ACL permissioning to fail?

Oh yeah, and how do I fix it? ;)

Brian




bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 12, 2011, 04:40:23 pm
Might as well finish off this conversation with myself.

Turns out that {$dao->$field} needs to be enclosed in '{$dao->$field}'. Not sure why, but it works.

Brian

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 12, 2011, 05:17:21 pm
Going to keep this thread going. Planning to write a blog post about this once I'm done.

I can't find anywhere in the documentation exactly what $type means in hook_civicrm_aclWhereClause.

As I previously mentioned, I now have the ACL working so that a user can search and view a list of contacts. However, when they click on a contact, I once again get a "DB Error: syntax error"

Previously, when searching for a contact, $type was 2. When I click on a contact name to view details $type is 1.

I don't know if $type has anything to do with my problems, but it would be nice to have some explanation of $type and the what the different numbers represent.

Brian


Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Help with ACL using Hooks
August 12, 2011, 09:03:01 pm

$type is typically a constant from CRM/Core/Permission.php, for the aclWhereClause it is either

CRM_Core_Permission::EDIT
CRM_Core_Permission::VIEW

can u please update the wiki docs:

http://wiki.civicrm.org/confluence/display/CRMDOC40/CiviCRM+hook+specification#CiviCRMhookspecification-hookcivicrmaclWhereClause

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 13, 2011, 09:19:34 am
Thanks Lobo. That got me pointed in the right direction.

So looking at Permission.php, I see that:
        EDIT   = 1,
        VIEW   = 2,
        DELETE = 3,
        CREATE = 4,
        SEARCH = 5,
        ALL    = 6,
        ADMIN  = 7;

So in my situation, when you click on a contact to view details, Civicrm is saying that the user needs an Edit permissions (as $type = 1) instead of when they conducted the search when they only needed the View permission ($type = 2).

Is this a bug? Shouldn't someone with view permissions be able to click on a contact name in the search results and view the details of the user? The same happens when I use the quick search box - the contact names will autocomplete since the user has the view permission, but when they click on the name they get denied because they don't have the edit permission.

Or am I just misunderstanding something here?

And where does civicrm look up the user permission level when using the aclWhereClause hook? I do have a custom field called permission level with a select box for each of the permission levels in Permission.php (+ a None for users with no permissions), but I'm just not using it yet, but I don't see how it should be pulled in when using the aclWhereClause for permissioning. I understand how permissioning works using the UI ACL - just not with the hook.



Brian
« Last Edit: August 13, 2011, 09:28:36 am by bpmccain »

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Help with ACL using Hooks
August 13, 2011, 09:27:37 am

yes, i noticed that discrepancy and am not sure why that is happening.

Any chance you can debug and figure out why Civi is requesting Edit permission on View contact

thanx

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 13, 2011, 09:29:13 am
I'll work on it - just wasn't sure if it was a bug, or it was just me  ;D

Hints as to where I might start looking would be good - I'm still learning my way around the files!
« Last Edit: August 13, 2011, 09:31:47 am by bpmccain »

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Help with ACL using Hooks
August 13, 2011, 10:36:30 am

i took a look at the code and realized that this is the right behavior :)

The code first checks for EDIT permission (for a view contact). If you have edit permission it can display more links. If edit permission is denied it then checks for VIEW permission

I debugged it by putting a backtrace in my function and seeing where the call was being made, so my hook looked like:

Code: [Select]
function civicrm_civicrm_aclWhereClause( $type, &$tables, &$whereTables, &$contactID, &$where ) {
    CRM_Core_Error::backtrace( );
    CRM_Core_Error::debug( 'T', $type );
    exit( );
}

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 13, 2011, 11:50:04 am
Thanks Lobo. I'll have to play around with this backtrace - never used it before!

bpmccain

  • I post frequently
  • ***
  • Posts: 255
  • Karma: 5
  • CiviCRM version: 4.1
  • CMS version: Drupal 7.12
  • MySQL version: 5.2
  • PHP version: 5.2
Re: Help with ACL using Hooks
August 13, 2011, 05:24:42 pm
So I needed to change the end of the example aclWhereClause hook implementation to"

Code: [Select]
if ( ! empty( $clauses ) ) {
        if ( ! empty( $where ) ) {
        $where .= ' AND '.implode( ' OR ', $clauses ).'';
    }
else {
$where .= ' '.implode( ' OR ', $clauses ).'';
}
}

in order to eliminate the possibility of having
Code: [Select]
AND AND
in my Query.

I've now got the aclWhereClause hook working to limit the subset of contacts that a logged in user can view.

Now I just need to figure out how to limit their pemissions so they can only view and not edit using the aclWhereClause hook.

I'll update all the documentation once I'm done and have a clearer view of how I got to where I am.

Donald Lobo

  • Administrator
  • I’m (like) Lobo ;)
  • *****
  • Posts: 15963
  • Karma: 470
    • CiviCRM site
  • CiviCRM version: 4.2+
  • CMS version: Drupal 7, Joomla 2.5+
  • MySQL version: 5.5.x
  • PHP version: 5.4.x
Re: Help with ACL using Hooks
August 13, 2011, 05:38:24 pm

cool. thanx for the feedback. Have fixed the example and will be part of the next release :)

lobo
A new CiviCRM Q&A resource needs YOUR help to get started. Visit our StackExchange proposed site, sign up and vote on 5 questions

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion »
  • APIs and Hooks (Moderator: Donald Lobo) »
  • Help with ACL using Hooks

This forum was archived on 2017-11-26.