CRM-19246 acl test for group.get api
authoreileenmcnaugton <eileen@fuzion.co.nz>
Fri, 19 Aug 2016 01:40:31 +0000 (13:40 +1200)
committereileen <emcnaughton@wikimedia.org>
Wed, 3 May 2017 07:54:09 +0000 (19:54 +1200)
CRM/ACL/API.php
CRM/Contact/BAO/Group.php
CRM/Contact/BAO/Query.php
CRM/Core/Config.php
CRM/Core/PseudoConstant.php
api/v3/Group.php
tests/phpunit/api/v3/ContactTest.php
tests/phpunit/api/v3/GroupTest.php

index c5ae1243cbf243bde82a2eef78f9ee166b3c8e1f..3337c4ab9b897c8846d2bcd028a46d2200e72ee1 100644 (file)
@@ -190,10 +190,8 @@ class CRM_ACL_API {
    * @param string $tableName
    * @param null $allGroups
    * @param null $includedGroups
-   * @param bool $flush
    *
-   * @return array
-   *   the ids of the groups for which the user has permissions
+   * @return bool
    */
   public static function groupPermission(
     $type,
@@ -201,39 +199,23 @@ class CRM_ACL_API {
     $contactID = NULL,
     $tableName = 'civicrm_saved_search',
     $allGroups = NULL,
-    $includedGroups = NULL,
-    $flush = FALSE
+    $includedGroups = NULL
   ) {
 
-    static $cache = array();
-    $groups = array();
-    //@todo this is pretty hacky!!!
-    //adding a way for unit tests to flush the cache
-    if ($flush) {
-      $cache = array();
-      return NULL;
+    if (!isset(Civi::$statics[__CLASS__]) || !isset(Civi::$statics[__CLASS__]['group_permission'])) {
+      Civi::$statics[__CLASS__]['group_permission'] = array();
     }
+
     if (!$contactID) {
-      $session = CRM_Core_Session::singleton();
-      $contactID = NULL;
-      if ($session->get('userID')) {
-        $contactID = $session->get('userID');
-      }
+      $contactID = CRM_Core_Session::singleton()->getLoggedInContactID();
     }
 
     $key = "{$tableName}_{$type}_{$contactID}";
-    if (array_key_exists($key, $cache)) {
-      $groups = &$cache[$key];
-    }
-    else {
-      $groups = self::group($type, $contactID, $tableName, $allGroups, $includedGroups);
-      $cache[$key] = $groups;
-    }
-    if (empty($groups)) {
-      return FALSE;
+    if (!array_key_exists($key, Civi::$statics[__CLASS__]['group_permission'])) {
+      Civi::$statics[__CLASS__]['group_permission'][$key] = self::group($type, $contactID, $tableName, $allGroups, $includedGroups);
     }
 
-    return in_array($groupID, $groups) ? TRUE : FALSE;
+    return in_array($groupID, Civi::$statics[__CLASS__]['group_permission'][$key]);
   }
 
 }
index c58b9ade639f0eb13831da5352cb462aa05403ab..6885eec95e27debc69a79b4200fe4128a9f562f4 100644 (file)
@@ -468,7 +468,7 @@ class CRM_Contact_BAO_Group extends CRM_Contact_DAO_Group {
       CRM_Contact_BAO_GroupOrganization::add($groupOrg);
     }
 
-    CRM_Utils_System::flushCache();
+    self::flushCaches();
     CRM_Contact_BAO_GroupContactCache::add($group->id);
 
     if (!empty($params['id'])) {
@@ -631,6 +631,25 @@ class CRM_Contact_BAO_Group extends CRM_Contact_DAO_Group {
     return $clause;
   }
 
+  /**
+   * Flush caches that hold group data.
+   *
+   * (Actually probably some overkill at the moment.)
+   */
+  protected static function flushCaches() {
+    CRM_Utils_System::flushCache();
+    $staticCaches = array(
+      'CRM_Core_PseudoConstant' => 'groups',
+      'CRM_ACL_API' => 'group_permission',
+      'CRM_ACL_BAO_ACL' => 'permissioned_groups',
+    );
+    foreach ($staticCaches as $class => $key) {
+      if (isset(Civi::$statics[$class][$key])) {
+        unset(Civi::$statics[$class][$key]);
+      }
+    }
+  }
+
   /**
    * @return string
    */
@@ -826,12 +845,8 @@ class CRM_Contact_BAO_Group extends CRM_Contact_DAO_Group {
    * @return array
    */
   public static function getGroupList(&$params) {
-    $config = CRM_Core_Config::singleton();
-
     $whereClause = self::whereClause($params, FALSE);
 
-    //$this->pagerAToZ( $whereClause, $params );
-
     $limit = "";
     if (!empty($params['rowCount']) &&
       $params['rowCount'] > 0
@@ -900,115 +915,108 @@ class CRM_Contact_BAO_Group extends CRM_Contact_DAO_Group {
     $visibility = CRM_Core_SelectValues::ufVisibility();
 
     while ($object->fetch()) {
-      $permission = CRM_Contact_BAO_Group::checkPermission($object->id, TRUE);
-      //@todo CRM-12209 introduced an ACL check in the whereClause function
-      // it may be that this checking is now obsolete - or that what remains
-      // should be removed to the whereClause (which is also accessed by getCount)
-
-      if ($permission) {
-        $newLinks = $links;
-        $values[$object->id] = array(
-          'class' => array(),
-          'count' => '0',
+      $newLinks = $links;
+      $values[$object->id] = array(
+        'class' => array(),
+        'count' => '0',
+      );
+      CRM_Core_DAO::storeValues($object, $values[$object->id]);
+
+      if ($object->saved_search_id) {
+        $values[$object->id]['title'] .= ' (' . ts('Smart Group') . ')';
+        // check if custom search, if so fix view link
+        $customSearchID = CRM_Core_DAO::getFieldValue(
+          'CRM_Contact_DAO_SavedSearch',
+          $object->saved_search_id,
+          'search_custom_id'
         );
-        CRM_Core_DAO::storeValues($object, $values[$object->id]);
-
-        if ($object->saved_search_id) {
-          $values[$object->id]['title'] .= ' (' . ts('Smart Group') . ')';
-          // check if custom search, if so fix view link
-          $customSearchID = CRM_Core_DAO::getFieldValue(
-            'CRM_Contact_DAO_SavedSearch',
-            $object->saved_search_id,
-            'search_custom_id'
-          );
-
-          if ($customSearchID) {
-            $newLinks[CRM_Core_Action::VIEW]['url'] = 'civicrm/contact/search/custom';
-            $newLinks[CRM_Core_Action::VIEW]['qs'] = "reset=1&force=1&ssID={$object->saved_search_id}";
-          }
+
+        if ($customSearchID) {
+          $newLinks[CRM_Core_Action::VIEW]['url'] = 'civicrm/contact/search/custom';
+          $newLinks[CRM_Core_Action::VIEW]['qs'] = "reset=1&force=1&ssID={$object->saved_search_id}";
         }
+      }
 
-        $action = array_sum(array_keys($newLinks));
+      $action = array_sum(array_keys($newLinks));
 
-        // CRM-9936
-        if (array_key_exists('is_reserved', $object)) {
-          //if group is reserved and I don't have reserved permission, suppress delete/edit
-          if ($object->is_reserved && !$reservedPermission) {
-            $action -= CRM_Core_Action::DELETE;
-            $action -= CRM_Core_Action::UPDATE;
-            $action -= CRM_Core_Action::DISABLE;
-          }
+      // CRM-9936
+      if (array_key_exists('is_reserved', $object)) {
+        //if group is reserved and I don't have reserved permission, suppress delete/edit
+        if ($object->is_reserved && !$reservedPermission) {
+          $action -= CRM_Core_Action::DELETE;
+          $action -= CRM_Core_Action::UPDATE;
+          $action -= CRM_Core_Action::DISABLE;
         }
+      }
 
-        if (array_key_exists('is_active', $object)) {
-          if ($object->is_active) {
-            $action -= CRM_Core_Action::ENABLE;
-          }
-          else {
-            $values[$object->id]['class'][] = 'disabled';
-            $action -= CRM_Core_Action::VIEW;
-            $action -= CRM_Core_Action::DISABLE;
-          }
+      if (array_key_exists('is_active', $object)) {
+        if ($object->is_active) {
+          $action -= CRM_Core_Action::ENABLE;
         }
+        else {
+          $values[$object->id]['class'][] = 'disabled';
+          $action -= CRM_Core_Action::VIEW;
+          $action -= CRM_Core_Action::DISABLE;
+        }
+      }
 
-        $action = $action & CRM_Core_Action::mask($groupPermissions);
+      $action = $action & CRM_Core_Action::mask($groupPermissions);
 
-        $values[$object->id]['visibility'] = $visibility[$values[$object->id]['visibility']];
+      $values[$object->id]['visibility'] = $visibility[$values[$object->id]['visibility']];
 
-        $groupsToCount[$object->saved_search_id ? 'civicrm_group_contact_cache' : 'civicrm_group_contact'][] = $object->id;
+      $groupsToCount[$object->saved_search_id ? 'civicrm_group_contact_cache' : 'civicrm_group_contact'][] = $object->id;
 
-        if (isset($values[$object->id]['group_type'])) {
-          $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR,
-            substr($values[$object->id]['group_type'], 1, -1)
-          );
-          $types = array();
-          foreach ($groupTypes as $type) {
-            $types[] = CRM_Utils_Array::value($type, $allTypes);
-          }
-          $values[$object->id]['group_type'] = implode(', ', $types);
-        }
-        $values[$object->id]['action'] = CRM_Core_Action::formLink($newLinks,
-          $action,
-          array(
-            'id' => $object->id,
-            'ssid' => $object->saved_search_id,
-          ),
-          ts('more'),
-          FALSE,
-          'group.selector.row',
-          'Group',
-          $object->id
+      if (isset($values[$object->id]['group_type'])) {
+        $groupTypes = explode(CRM_Core_DAO::VALUE_SEPARATOR,
+          substr($values[$object->id]['group_type'], 1, -1)
         );
-
-        // If group has children, add class for link to view children
-        $values[$object->id]['is_parent'] = FALSE;
-        if (array_key_exists('children', $values[$object->id])) {
-          $values[$object->id]['class'][] = "crm-group-parent";
-          $values[$object->id]['is_parent'] = TRUE;
+        $types = array();
+        foreach ($groupTypes as $type) {
+          $types[] = CRM_Utils_Array::value($type, $allTypes);
         }
+        $values[$object->id]['group_type'] = implode(', ', $types);
+      }
+      $values[$object->id]['action'] = CRM_Core_Action::formLink($newLinks,
+        $action,
+        array(
+          'id' => $object->id,
+          'ssid' => $object->saved_search_id,
+        ),
+        ts('more'),
+        FALSE,
+        'group.selector.row',
+        'Group',
+        $object->id
+      );
 
-        // If group is a child, add child class
-        if (array_key_exists('parents', $values[$object->id])) {
-          $values[$object->id]['class'][] = "crm-group-child";
-        }
+      // If group has children, add class for link to view children
+      $values[$object->id]['is_parent'] = FALSE;
+      if (array_key_exists('children', $values[$object->id])) {
+        $values[$object->id]['class'][] = "crm-group-parent";
+        $values[$object->id]['is_parent'] = TRUE;
+      }
 
-        if ($groupOrg) {
-          if ($object->org_id) {
-            $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->org_id}");
-            $values[$object->id]['org_info'] = "<a href='{$contactUrl}'>{$object->org_name}</a>";
-          }
-          else {
-            $values[$object->id]['org_info'] = ''; // Empty cell
-          }
+      // If group is a child, add child class
+      if (array_key_exists('parents', $values[$object->id])) {
+        $values[$object->id]['class'][] = "crm-group-child";
+      }
+
+      if ($groupOrg) {
+        if ($object->org_id) {
+          $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->org_id}");
+          $values[$object->id]['org_info'] = "<a href='{$contactUrl}'>{$object->org_name}</a>";
         }
         else {
-          $values[$object->id]['org_info'] = NULL; // Collapsed column if all cells are NULL
-        }
-        if ($object->created_id) {
-          $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->created_id}");
-          $values[$object->id]['created_by'] = "<a href='{$contactUrl}'>{$object->created_by}</a>";
+          $values[$object->id]['org_info'] = ''; // Empty cell
         }
       }
+      else {
+        $values[$object->id]['org_info'] = NULL; // Collapsed column if all cells are NULL
+      }
+      if ($object->created_id) {
+        $contactUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$object->created_id}");
+        $values[$object->id]['created_by'] = "<a href='{$contactUrl}'>{$object->created_by}</a>";
+      }
     }
 
     // Get group counts - executes one query for regular groups and another for smart groups
index b72e793f39855f08fc256bce40b2ac76b1524285..d519eeef4337ece4ca1925e44d9af1ad98d4979d 100644 (file)
@@ -6322,14 +6322,8 @@ AND   displayRelType.is_active = 1
    */
   public function convertGroupIDStringToLabelString(&$dao, $val) {
     $groupIDs = explode(',', $val);
-
-    // The pseudoConstant function does not actually cache.
-    static $allGroups;
-    if (!$allGroups) {
-      $allGroups = CRM_Core_PseudoConstant::group();
-    }
     // Note that groups that the user does not have permission to will be excluded (good).
-    $groups = array_intersect_key($allGroups, array_flip($groupIDs));
+    $groups = array_intersect_key(CRM_Core_PseudoConstant::group(), array_flip($groupIDs));
     return implode(', ', $groups);
 
   }
index 33c2f3bfd1f3afff02ca57330a1a9e05632ab90c..3d82d8fd7b566b59b2f067a585b4e0c4019e06c5 100644 (file)
@@ -44,6 +44,7 @@ require_once 'api/api.php';
  * Class CRM_Core_Config
  *
  * @property CRM_Utils_System_Base $userSystem
+ * @property CRM_Core_Permission_Base $userPermissionClass
  * @property array $enableComponents
  * @property array $languageLimit
  * @property bool $debug
index d28aecec12a5c3a1fcb2a7776b354c0532cb3d8a..419664441890c1f4f2c3d5e8a4e65c227e0b8cad 100644 (file)
@@ -909,18 +909,12 @@ WHERE  id = %1";
    */
   public static function allGroup($groupType = NULL, $excludeHidden = TRUE) {
     $condition = CRM_Contact_BAO_Group::groupTypeCondition($groupType, $excludeHidden);
-
-    if (!self::$group) {
-      self::$group = array();
-    }
-
     $groupKey = ($groupType ? $groupType : 'null') . !empty($excludeHidden);
 
-    if (!isset(self::$group[$groupKey])) {
-      self::$group[$groupKey] = NULL;
-      self::populate(self::$group[$groupKey], 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition);
+    if (!isset(Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey])) {
+      self::populate(Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey], 'CRM_Contact_DAO_Group', FALSE, 'title', 'is_active', $condition);
     }
-    return self::$group[$groupKey];
+    return Civi::$statics[__CLASS__]['groups']['allGroup'][$groupKey];
   }
 
   /**
index 8538a33c4b08a093ec7e100bef8d8e8a8210060f..9e6449e82ad38c46ee29970bcd9b7a12aac3c893 100644 (file)
@@ -71,8 +71,10 @@ function _civicrm_api3_group_create_spec(&$params) {
  */
 function civicrm_api3_group_get($params) {
   $options = _civicrm_api3_get_options_from_params($params, TRUE, 'Group', 'get');
-  if ((empty($options['return']) || !in_array('member_count', $options['return'])) && empty($params['check_permissions'])) {
-    return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, TRUE, 'Group');
+
+  if ($options['is_count']) {
+    $params['options']['is_count'] = 0;
+    $params['return'] = 'id';
   }
 
   $groups = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, 'Group');
@@ -80,7 +82,7 @@ function civicrm_api3_group_get($params) {
     if (!empty($params['check_permissions']) && !CRM_Contact_BAO_Group::checkPermission($group['id'])) {
       unset($groups[$id]);
     }
-    elseif (!empty($options['return']) && in_array('member_count', $options['return'])) {
+    if (!empty($options['return']) && in_array('member_count', $options['return'])) {
       $groups[$id]['member_count'] = CRM_Contact_BAO_Group::memberCount($id);
     }
   }
index 3733886aace084242927cc29064d405e973819c8..59936149f4c8d1260487a0f1b1422508f1ee2c3e 100644 (file)
@@ -3250,7 +3250,7 @@ class api_v3_ContactTest extends CiviUnitTestCase {
         'contact_id' => $created_contact_id,
         'group_id' => $create_group['id'],
       );
-      $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
+      $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
       $contact_get = $this->callAPISuccess('contact', 'get', array('group' => $title, 'return' => 'group'));
       $this->assertEquals(1, $contact_get['count']);
       $this->assertEquals($created_contact_id, $contact_get['id']);
index 1860085cc6f4663a677f7b7cd757ce4790a921d6..f03f05a25e624b54aa3377c9ad71c9d9b80179a1 100644 (file)
  * @group headless
  */
 class api_v3_GroupTest extends CiviUnitTestCase {
-  protected $_apiversion;
+  protected $_apiversion = 3;
   protected $_groupID;
 
+  /**
+   * Set up for tests.
+   */
   public function setUp() {
-    $this->_apiversion = 3;
-
     parent::setUp();
     $this->_groupID = $this->groupCreate();
+    $config = CRM_Core_Config::singleton();
+    $config->userPermissionClass->permissions = array();
   }
 
+  /**
+   * Clean up after test.
+   */
   public function tearDown() {
-
     $this->groupDelete($this->_groupID);
+    CRM_Utils_Hook::singleton()->reset();
+    $config = CRM_Core_Config::singleton();
+    unset($config->userPermissionClass->permissions);
   }
 
-  public function testgroupCreateNoTitle() {
+  /**
+   * Test missing required title parameter results in an error.
+   */
+  public function testGroupCreateNoTitle() {
     $params = array(
       'name' => 'Test Group No title ',
       'domain_id' => 1,
@@ -60,12 +71,12 @@ class api_v3_GroupTest extends CiviUnitTestCase {
       ),
     );
 
-    $group = $this->callAPIFailure('group', 'create', $params, 'Mandatory key(s) missing from params array: title');
+    $this->callAPIFailure('group', 'create', $params, 'Mandatory key(s) missing from params array: title');
   }
 
 
   public function testGetGroupWithEmptyParams() {
-    $group = $this->callAPISuccess('group', 'get', $params = array());
+    $group = $this->callAPISuccess('group', 'get', array());
 
     $group = $group["values"];
     $this->assertNotNull(count($group));
@@ -213,10 +224,36 @@ class api_v3_GroupTest extends CiviUnitTestCase {
     $params['parents'] = array();
     $params['parents'][$this->_groupID] = 'test Group';
     $params['parents']["(SELECT api_key FROM civicrm_contact where id = 1)"] = "Test";
-    $group2 = $this->callAPIFailure('group', 'create', $params);
+    $this->callAPIFailure('group', 'create', $params);
     unset($params['parents']["(SELECT api_key FROM civicrm_contact where id = 1)"]);
     $group2 = $this->callAPISuccess('group', 'create', $params);
     $this->assertEquals(count($group2['values'][$group2['id']]['parents']), 1);
   }
 
+  /**
+   * Test that ACLs are applied to group.get calls.
+   */
+  public function testGroupGetACLs() {
+    $this->createLoggedInUser();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM');
+    $this->callAPISuccessGetCount('Group', array('check_permissions' => 1), 0);
+    $this->hookClass->setHook('civicrm_aclGroup', array($this, 'aclGroupAllGroups'));
+    unset(Civi::$statics['CRM_ACL_API']['group_permission']);
+    $this->callAPISuccessGetCount('Group', array('check_permissions' => 1), 1);
+  }
+
+  /**
+   * Implement hook to restrict to test group 1.
+   *
+   * @param string $type
+   * @param int $contactID
+   * @param string $tableName
+   * @param array $allGroups
+   * @param array $ids
+   */
+  public function aclGroupAllGroups($type, $contactID, $tableName, $allGroups, &$ids) {
+    $group = $this->callAPISuccess('Group', 'get', array('name' => 'Test Group 1'));
+    $ids = array_keys($group['values']);
+  }
+
 }