Uploaded image for project: 'CiviCRM'
  1. CiviCRM
  2. CRM-10667

Users with ACLs & participant based smart groups cannot see groups on groups tab.

    Details

    • Type: Bug
    • Status: Done/Fixed
    • Priority: Minor
    • Resolution: Fixed/Completed
    • Affects Version/s: 4.2.0
    • Fix Version/s: 4.3.0
    • Component/s: Core CiviCRM
    • Labels:
      None

      Description

      This is a variant of a problem I have been struggling to pin down - but in this case I can consistently replicate it on 4.2. In order to determine which groups can be viewed by an ACL-permissioned user a query which resolves viewable smart groups is used. In this case the query contains an inner join on the event table and no data is returned due to the inner join.

      The situation is that the user does not have 'view all contacts permission' but they DO have permission to see contacts via an ACL hook.

      One of the groups they are permitted to see is a smart group of all participants in a particular event. This results in them not being able to see groups of any contact who is not a participant wherever they are rendered by the function.

      I am using the multisite module here - although the problem would affect any usage of ACLs based on their event participation

      CRM_Contact_BAO_GroupContact::getContactGroup();

      ie. on the group tab of the dashboard the group list incorrectly shows as no groups (CRM_Contact_Page_View_GroupContact::browse()). The query that doesn't show the groups is called by
      $in = CRM_Contact_BAO_GroupContact::getContactGroup($this->_contactId, 'Added');

      $permission = CRM_Core_Permission::whereClause(CRM_Core_Permission::VIEW, $tables, $whereTables);

      &&

      $from = CRM_Contact_BAO_Query::fromClause($tables);

      The first query identifies the civicrm_event table as one of the tables for the from clause. The from clause eventually gets the join to civicrm_event from CRM_Event_BAO_Query::from();

      THE JOIN IT USES IS AN INNER JOIN & hence the query is empty.

      The query generated is below (NB this example is pretty modest - but on sites with a large number of smart groups this query can become very long & large)

      SELECT COUNT(DISTINCT civicrm_group_contact.id)
      FROM civicrm_contact contact_a
      LEFT JOIN civicrm_address ON (contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1)
      LEFT JOIN civicrm_state_province ON civicrm_address.state_province_id = civicrm_state_province.id
      LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id
      LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1)
      LEFT JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1)
      LEFT JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1)
      LEFT JOIN civicrm_group_contact ON contact_a.id = civicrm_group_contact.contact_id
      LEFT JOIN civicrm_group ON civicrm_group.id = civicrm_group_contact.group_id
      LEFT JOIN civicrm_subscription_history ON civicrm_group_contact.contact_id = civicrm_subscription_history.contact_id AND civicrm_group_contact.group_id = civicrm_subscription_history.group_id
      LEFT JOIN civicrm_participant ON civicrm_participant.contact_id = contact_a.id
      INNER JOIN civicrm_event ON civicrm_participant.event_id = civicrm_event.id
      LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id
      LEFT JOIN civicrm_value_media_info_34 ON civicrm_value_media_info_34.entity_id = contact_a.id
      LEFT JOIN civicrm_option_group option_group_gender ON (option_group_gender.name = 'gender')
      LEFT JOIN civicrm_option_value gender ON (contact_a.gender_id = gender.value AND option_group_gender.id = gender.option_group_id)
      LEFT JOIN civicrm_option_group option_group_prefix ON (option_group_prefix.name = 'individual_prefix')
      LEFT JOIN civicrm_option_value individual_prefix ON (contact_a.prefix_id = individual_prefix.value AND option_group_prefix.id = individual_prefix.option_group_id)
      LEFT JOIN civicrm_option_group option_group_suffix ON (option_group_suffix.name = 'individual_suffix')
      LEFT JOIN civicrm_option_value individual_suffix ON (contact_a.suffix_id = individual_suffix.value AND option_group_suffix.id = individual_suffix.option_group_id)
      WHERE contact_a.id = 10590 AND civicrm_group.is_active = 1 AND civicrm_group.is_hidden = 0 AND civicrm_group_contact.status = 'Added' AND ((civicrm_group_contact.group_id IN (41, 45, 46, 66, 70, 71, 78, 81, 82, 83, 88, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131) AND civicrm_group_contact.status = 'Added') OR (LOWER(civicrm_worldregion.name) = 'europe' AND contact_a.contact_type IN ('Organization') AND ((contact_a.contact_sub_type LIKE '%Party%'))) OR (civicrm_value_media_info_34.media_type_283 = 'agency') OR (civicrm_event.id = 20 AND civicrm_participant.status_id = 1 AND civicrm_participant.is_test = 0) OR (civicrm_event.id = 20 AND civicrm_participant.status_id = 1 AND civicrm_participant.is_test = 0))

      The saved_search entry looks like

      INSERT INTO `civicrm_saved_search` (`id`, `form_values`, `mapping_id`, `search_custom_id`, `where_clause`, `select_tables`, `where_tables`) VALUES (37, 'a:127:{s:5:"qfKey";s:37:"fa6ad47e5bc8d14b6994a495cd0956b9_5745";s:12:"hidden_basic";s:1:"1";s:12:"contact_type";a:0:{}s:5:"group";a:0:{}s:12:"contact_tags";a:0:{}s:9:"sort_name";s:0:"";s:5:"email";s:0:"";s:14:"contact_source";s:0:"";s:9:"job_title";s:0:"";s:7:"uf_user";s:0:"";s:11:"uf_group_id";s:0:"";s:14:"component_mode";s:1:"3";s:8:"operator";s:3:"AND";s:25:"display_relationship_type";s:0:"";s:7:"privacy";a:6:

      {s:12:"do_not_phone";s:0:"";s:12:"do_not_email";s:0:"";s:11:"do_not_mail";s:0:"";s:10:"do_not_sms";s:0:"";s:12:"do_not_trade";s:0:"";s:13:"do_not_toggle";s:0:"";}

      s:13:"email_on_hold";a:1:

      {s:7:"on_hold";s:0:"";}

      s:30:"preferred_communication_method";a:5:

      {i:1;s:0:"";i:2;s:0:"";i:3;s:0:"";i:4;s:0:"";i:5;s:0:"";}

      s:18:"preferred_language";s:0:"";s:13:"hidden_custom";s:1:"1";s:10:"custom_149";s:0:"";s:10:"custom_150";s:0:"";s:10:"custom_151";s:0:"";s:10:"custom_152";s:0:"";s:14:"custom_58_from";s:0:"";s:12:"custom_58_to";s:0:"";s:14:"custom_61_from";s:0:"";s:12:"custom_61_to";s:0:"";s:14:"custom_62_from";s:0:"";s:12:"custom_62_to";s:0:"";s:9:"custom_64";s:0:"";s:9:"custom_66";a:0:{}s:9:"custom_67";s:0:"";s:9:"custom_68";s:0:"";s:9:"custom_69";a:0:{}s:9:"custom_70";s:0:"";s:9:"custom_79";s:0:"";s:9:"custom_72";s:0:"";i:1;s:0:"";s:10:"custom_148";a:1:

      {i:1;s:0:"";}

      s:10:"custom_153";s:0:"";s:10:"custom_154";s:0:"";s:10:"custom_155";s:0:"";s:10:"custom_156";s:0:"";s:10:"custom_157";s:0:"";s:10:"custom_158";s:0:"";s:10:"custom_159";s:0:"";s:10:"custom_160";s:0:"";s:10:"custom_161";s:0:"";s:10:"custom_162";s:0:"";s:10:"custom_164";s:0:"";s:10:"custom_165";s:0:"";s:10:"custom_166";s:0:"";s:10:"custom_167";s:0:"";s:10:"custom_168";s:0:"";s:10:"custom_170";s:0:"";s:10:"custom_172";s:0:"";s:10:"custom_173";s:0:"";s:15:"custom_174_from";s:0:"";s:13:"custom_174_to";s:0:"";s:10:"custom_208";s:0:"";s:10:"custom_209";s:0:"";s:10:"custom_210";s:0:"";s:10:"custom_211";s:0:"";s:10:"custom_212";s:0:"";s:10:"custom_213";s:0:"";s:10:"custom_214";s:0:"";s:10:"custom_215";s:0:"";s:10:"custom_216";s:0:"";s:10:"custom_217";s:0:"";s:10:"custom_218";s:0:"";s:10:"custom_221";s:0:"";s:10:"custom_219";s:0:"";s:8:"amendors";s:0:"";s:9:"delegates";s:0:"";s:7:"intsect";s:0:"";s:13:"CiviCRM_OP_OR";s:0:"";s:10:"custom_253";a:4:

      {s:8:"amendors";s:0:"";s:9:"delegates";s:0:"";s:7:"intsect";s:0:"";s:13:"CiviCRM_OP_OR";s:0:"";}

      s:16:"hidden_CiviEvent";s:1:"1";s:10:"event_name";s:35:"Copenhagen EGP Council Meeting 2012";s:10:"event_type";s:0:"";s:21:"participant_fee_level";s:0:"";s:8:"event_id";s:2:"20";s:13:"event_type_id";s:0:"";s:18:"participant_fee_id";s:0:"";s:20:"event_start_date_low";s:0:"";s:19:"event_end_date_high";s:0:"";s:21:"participant_status_id";a:1:

      {i:1;s:1:"1";}

      s:26:"participant_fee_amount_low";s:0:"";s:27:"participant_fee_amount_high";s:0:"";s:9:"custom_78";s:0:"";s:1:"a";s:0:"";s:9:"custom_73";a:1:

      {s:1:"a";s:0:"";}

      s:9:"custom_74";s:0:"";s:15:"custom_224_from";s:0:"";s:13:"custom_224_to";s:0:"";s:15:"custom_226_from";s:0:"";s:13:"custom_226_to";s:0:"";s:15:"custom_259_from";s:0:"";s:20:"custom_259_from_time";s:0:"";s:13:"custom_259_to";s:0:"";s:18:"custom_259_to_time";s:0:"";s:15:"custom_260_from";s:0:"";s:20:"custom_260_from_time";s:0:"";s:13:"custom_260_to";s:0:"";s:18:"custom_260_to_time";s:0:"";s:10:"custom_262";s:0:"";s:10:"custom_263";s:0:"";s:3:"yes";s:0:"";s:10:"custom_264";a:1:

      {s:3:"yes";s:0:"";}

      s:10:"custom_275";s:0:"";s:10:"custom_276";a:1:

      {s:3:"yes";s:0:"";}

      s:10:"custom_277";s:0:"";s:10:"custom_279";s:0:"";s:10:"custom_280";s:0:"";s:10:"custom_270";s:0:"";s:15:"custom_271_from";s:0:"";s:20:"custom_271_from_time";s:0:"";s:13:"custom_271_to";s:0:"";s:18:"custom_271_to_time";s:0:"";s:15:"custom_272_from";s:0:"";s:20:"custom_272_from_time";s:0:"";s:13:"custom_272_to";s:0:"";s:18:"custom_272_to_time";s:0:"";s:10:"custom_273";s:0:"";s:10:"custom_274";a:1:

      {s:3:"yes";s:0:"";}

      s:4:"task";s:2:"13";s:8:"radio_ts";s:6:"ts_all";}', NULL, NULL, ' ( civicrm_event.id = 20 AND civicrm_participant.status_id = 1 AND civicrm_participant.is_test = 0 ) ', 'a:13:

      {s:15:"civicrm_contact";i:1;s:15:"civicrm_address";i:1;s:22:"civicrm_state_province";i:1;s:15:"civicrm_country";i:1;s:13:"civicrm_email";i:1;s:13:"civicrm_phone";i:1;s:10:"civicrm_im";i:1;s:19:"civicrm_participant";i:1;s:13:"civicrm_event";i:1;s:19:"civicrm_worldregion";i:1;s:6:"gender";i:1;s:17:"individual_prefix";i:1;s:17:"individual_suffix";i:1;}

      ', 'a:3:

      {s:15:"civicrm_contact";i:1;s:19:"civicrm_participant";i:1;s:13:"civicrm_event";i:1;}

      ');

      I'm not too sure the best approach to this - at the multisite module level being able to identify which smart groups should be target groups & which should not would be helpful - in which case i would just not give this group 'type 3' or whatever & it would be identified as listable in things like the group tab but not not requiring resolution.

      However, I guess in this situation the issue is that we are trying to identify which groups a contact should be able to see - not the contacts within them so potentially

      CRM_Core_Permission_Drupal::group

      needs to understand if it is being called in order to find groups or contacts. ie if it is being called in order to determine the viewable groups then it shouldn't be resolving smart groups as they are not material to the viewable group list.

        Attachments

          Activity

            People

            • Assignee:
              lobo Donald A. Lobo
              Reporter:
              eileen Eileen McNaughton
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: