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 (Moderator: Donald Lobo) »
  • Row permissions for events
Pages: [1]

Author Topic: Row permissions for events  (Read 692 times)

jere

  • I post occasionally
  • **
  • Posts: 41
  • Karma: 1
  • CiviCRM version: 4.3.3
  • CMS version: Drupal 7.22
  • MySQL version: 5.5.31
  • PHP version: 5.3.10
Row permissions for events
January 13, 2014, 11:17:00 am
Is there a way to restrict access to events based on the value of a custom field associated with the event for users of a specific contact_sub_type without modifying core files?

Thanks
« Last Edit: January 13, 2014, 11:19:10 am by jere »

totten

  • Administrator
  • Ask me questions
  • *****
  • Posts: 695
  • Karma: 64
Re: Row permissions for events
January 14, 2014, 02:18:32 pm
Well, it helps to distinguish:

a) Is the goal to restrict a particular screen or use-case -- e.g. to limit access to the registration screen?

b) Is the goal to add configurability for a range of (possibly-not-well-defined) use-cases and screens?

It's much easier to restrict a particular screen or use-case. For example, you can write a module or extension (outside core) which uses the hooks and the API. In particular, hook_civicrm_buildForm ( http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_buildForm ) or hook_civicrm_pageRun ( http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_pageRun ) are called on each page-view, and you can use the hook data to figure out if the user is trying to access the event-registration screen. If so, you can determine the event ID and  current user ID, perform some lookups, and throw a fatal error if the user is unauthorized. Pseudocode:

Code: [Select]
function mymodule_civicrm_buildForm($formName, &$form) {
  if ($formName == 'The_Event_Registration_Form') {
    $event = civicrm_api3('Event', 'get', array(
      'id' => $form->the_event_id_property
    ));
    $contact = civicrm_api3('Contact', 'get', array(
      'id' => $the_current_user_id
    ));
    if ($contact does not have access to $event) {
      CRM_Core_Error::fatal(ts('Not authorized'));
    }
  }
}

The hooks are a bit under-documented. (That's why I'm writing pseudocode instead of real code.) To figure out how to use them, it's helpful to install these two modules:

 * http://drupal.org/project/devel
 * https://github.com/eileenmcnaughton/civicrm_developer

As you browse through the site, you'll see notices about the various hooks that fire and the information available in each, and you can use that to write proper code.

jere

  • I post occasionally
  • **
  • Posts: 41
  • Karma: 1
  • CiviCRM version: 4.3.3
  • CMS version: Drupal 7.22
  • MySQL version: 5.5.31
  • PHP version: 5.3.10
Re: Row permissions for events
January 15, 2014, 08:24:52 am
This is helpful for my understanding, but I need to provide you better information.

The organization that is using the site has a small number of outside organizations that are sometimes involved with events and there is a desire to grant a representative from those organizations access to those events with which they are involved. So, the outside representative could see and edit events with which they are involved, but not others.

The problem I face (in my limited understanding) is that the query that creates the list of organizations events when a user accesses Manage Events is buried in  CRM/Event/Page/ManageEvent.php. I don't see how the hooks would help me with modifying the list of events returned. If I had to, I see how I could modify the query in ManageEvent.php to deliver the correct list of events, but that would leave me (or some future person) with difficulties later.

Maybe I should create a new profile to use instead of the ManageEvent page and try to link back into the core functionality after an event selection was made from that profile?  Then I can use the hooks you mentioned to protect against attempts to access events other than the ones they are associated with.




« Last Edit: January 16, 2014, 07:18:35 pm by jere »

jere

  • I post occasionally
  • **
  • Posts: 41
  • Karma: 1
  • CiviCRM version: 4.3.3
  • CMS version: Drupal 7.22
  • MySQL version: 5.5.31
  • PHP version: 5.3.10
Re: Row permissions for events
January 23, 2014, 01:41:55 pm
totten,

You reply turned out to be quite helpful. Thanks. I was able to use the hook_civicrm_aclGroup to reduce the events displayed by the search in ManageEvents by designating which events to show by permissions. The links leading to individual events were easier too. I also used the  hook_civicrm_buildForm and a couple of extra.tpl files for templates where I needed to make minor changes.

However, although the permissions function is called in the browse function which in turn called the hook_civicrm_aclGroup for CRM_Event_Page_ManageEven, it is not called in the pager functions. So although it displayed the reduced set of events that I wanted that group of users to see, the pager functions were still based on the entire list of events. I fixed it by inserting a line of code in the two pager functions, but I think it might be a bug. If the permissions can be used in the manage events it should be used in the pagers too.

Anyway, Thanks to your help. Without it I may have ended up with a bit of a mess.

sonicthoughts

  • Ask me questions
  • ****
  • Posts: 498
  • Karma: 10
Re: Row permissions for events
April 01, 2014, 03:18:45 am
Hi - jere
I\m facing a similar need.  Restrict registration of set of events by type.  Civicrm-webform could do it, but we are using civicrm native listings already.  Would you mind sharing your code?  If you could add here: http://wiki.civicrm.org/confluence/display/CRMDOC/Cookbooks or post to this forum and I will (when I integrate it) - that would be great!

jere

  • I post occasionally
  • **
  • Posts: 41
  • Karma: 1
  • CiviCRM version: 4.3.3
  • CMS version: Drupal 7.22
  • MySQL version: 5.5.31
  • PHP version: 5.3.10
Re: Row permissions for events
April 01, 2014, 08:23:57 pm
Hi sonicthoughts,

I ended up changing my approach a bit from that post. It turned out what I had done did not work so well after all. I could not figure out a good way to avoid modifying the civicrm files (a copy in my custom php directory) , but I am a bit new to civicrm so others more knowledgeable are likely to know better ways. When I recently updated, I had to do a diff from my copy to the new version coming with the upgrade to see if what I did was impacted by the upgrade. It turned out there was not any impact, so I simply copied my added lines to the new version. But it is a new step and someone else who upgrades later may fail to check this.

But here is what I did to restrict the events output based on the user's contact sub type (not the event type). In this use case the organization that owns the site promotes products at events by providing free samples for a distributor. Among the custom values associated with the event is a contact id of the distributor of the products (an organization contact type). The representative of the distributor has a relationship to that distributor contact through the civicrm_relationship table with a relationship type in the civicrm_relationship_type table. These were both added through the normal civicrm pages. The representative is an individual contact type with a  contact_sub_type of distributor_rep. (I changed the variable names in this post from the ones actually used in the code.)

I basically add a clause to the where clause being generated in the whereClause function in CRM/Event/Page/ManageEvent.php by calling a function in my custom module file as follows:

Added to ManageEvent.php at line 490 of version 4.4:
Code: [Select]
    $filterclause = mymodule_manage_event_where_clause();
    if ( !empty( $filterclause ) ) {
      $clauses[] = $filterclause;
    }

The mymodule_manage_event_where_clause() was done in some haste and needs rework, but here it is:

The mymodule_getSubTypes ($contactID) returns an array of contact sub types for the current user. In retrospect I should probably change this to use CRM_Contact_BAO_ContactType::subTypes but was not aware of it at the time.

Caveats:  The relationship subtype is hard coded to the id of the relationship_type (26) in civicrm_relationship_type table. This could cause problems and should perhaps be changed using a lookup or by adding another join to the civicrm_relationship_type and filtering based on the relationship type name to make it portable. Or there may be betters ways. I also used the name created by the system for the custom value table and the column names which would surely differ if used elsewhere. This may need to be changed using a lookup of the table and column names if you want something more portable. You also need to make the relationship types go the right direction (distributor rep is representative for organization distributor) or you would need to use contact_id_a where I used contact_id_b and vice versa.

Code: [Select]
function mymodule_manage_event_where_clause () {
  $session = & CRM_Core_Session::singleton();
  $contactID = $session->get( 'userID' ); // which is contact id of the user
  $retSubTypes = mymodule_getSubTypes( $contactID );
  if ( array_key_exists( 'Distributor_Rep', array_flip( $retSubTypes['contact_sub_type'] ) ) ) {
    $params = array(
        'version' => 3,
        'sequential' => 0,
        'relationship_type_id' => 26,
        'contact_id_a' => $contactID,
    );
    $result = civicrm_api( 'Relationship', 'getsingle', $params );
    if ( 1 == CRM_Utils_Array::value( 'is_error', $result ) ) {
      CRM_Core_Error::fatal( $result['error_message'] . ' in module' );
    }
    $distributor_id = $result['contact_id_b'];
    $whereclause = "
      id IN (select e.id from civicrm_event e
inner join civicrm_value_event_records_4 er ON e.id = er.entity_id
where er.distributor_11 ='{$distributor_id}')
    ";
    return $whereclause;
  }
  return NULL;
}



There were other changes related to what to show in the page to this user like hiding links that I did not want the distributor rep to have access to. These were done to the extent I could in a ManageEvent.extras.tpl using jquery to hide them. For those my simple mind could not get to work using jquery, I hid by assigning a value to a variable in the template using mymodule_civicrm_pageRun hook and wrapping the sections I did not want to show by using that variable value to see if the current user was a distributor rep or not. There were also things to hide in the edit page if the user had a link to edit and access to edit.

I also added permissions to this user sub_type group to all events which I then reduced in the way described above.

There is no public access to any civicrm module pages in this site, nor access for a simple authenticated user type. It is used only internally to manage the promotions with different access to people with different roles. This customer does not currently manage public access to events themselves. For more open sites, permissions may need to be different. I don't know.

Pages: [1]
  • CiviCRM Community Forums (archive) »
  • Old sections (read-only, deprecated) »
  • Developer Discussion (Moderator: Donald Lobo) »
  • Row permissions for events

This forum was archived on 2017-11-26.