}
CRM_Contact_BAO_GroupContactCache::check($smartGroups);
-
+ $aclFilter = NULL;
+ $selectWhereClauses = array_filter(CRM_Contact_BAO_Group::getSelectWhereClause('group'));
+ $aclFilter = implode(' AND ', $selectWhereClauses);
+ $aclFilter = !empty($aclFilter) ? ' AND ' . $aclFilter : '';
$smartGroupQuery = '';
if (!empty($smartGroups)) {
$smartGroups = implode(',', $smartGroups);
$smartGroupQuery = " UNION DISTINCT
SELECT DISTINCT smartgroup_contact.contact_id
FROM civicrm_group_contact_cache smartgroup_contact
- WHERE smartgroup_contact.group_id IN ({$smartGroups}) ";
+ INNER JOIN civicrm_group group ON group.id = smartgroup_contact.group_id
+ WHERE smartgroup_contact.group_id IN ({$smartGroups}) {$aclFilter}";
}
$sqlOp = $this->getSQLOperator($op);
return " {$contactAlias}.id {$sqlOp} (
SELECT DISTINCT {$this->_aliases['civicrm_group']}.contact_id
FROM civicrm_group_contact {$this->_aliases['civicrm_group']}
- WHERE {$clause} AND {$this->_aliases['civicrm_group']}.status = 'Added'
+ INNER JOIN civicrm_group group ON group.id = smartgroup_contact.group_id
+ WHERE {$clause} AND {$this->_aliases['civicrm_group']}.status = 'Added' {$aclFilter}
{$smartGroupQuery} ) ";
}
$ret = [];
foreach ($this->selectedTables() as $tableName) {
$baoName = str_replace('_DAO_', '_BAO_', (CRM_Core_DAO_AllCoreTables::getClassForTable($tableName) ?? ''));
+ // Do not include CiviCRM group add Select Where clause because we don't necessarily join here for reports with optimisedGroupFilters
+ if ($baoName === 'CRM_Contact_BAO_Group') {
+ continue;
+ }
if ($baoName && class_exists($baoName) && !empty($this->_columns[$tableName]['alias'])) {
$tableAlias = $this->_columns[$tableName]['alias'];
$clauses = array_filter($baoName::getSelectWhereClause($tableAlias));
protected $contactIDs = [];
+ protected $aclGroupId = NULL;
+
/**
* Our group reports use an alter so transaction cleanup won't work.
*
$this->quickCleanUpFinancialEntities();
$this->quickCleanup(['civicrm_group', 'civicrm_saved_search', 'civicrm_group_contact', 'civicrm_group_contact_cache', 'civicrm_group'], TRUE);
(new CRM_Logging_Schema())->dropAllLogTables();
+ CRM_Utils_Hook::singleton()->reset();
+ $config = CRM_Core_Config::singleton();
+ unset($config->userPermissionClass->permissions);
parent::tearDown();
}
$this->assertNumberOfContactsInResult(1, $rows, $template);
}
+ /**
+ * Test the group filter works on various reports when ACLed user is in play
+ *
+ * @dataProvider getMembershipAndContributionReportTemplatesForGroupTests
+ *
+ * @param string $template
+ * Report template unique identifier.
+ *
+ * @throws \CRM_Core_Exception
+ */
+ public function testReportsWithNonSmartGroupFilterWithACL($template) {
+ $this->aclGroupId = $this->setUpPopulatedGroup();
+ $this->createLoggedInUser();
+ CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM'];
+ $this->callAPISuccessGetCount('Group', ['check_permissions' => 1], 0);
+ $this->hookClass->setHook('civicrm_aclGroup', [$this, 'aclGroupOnly']);
+ $this->hookClass->setHook('civicrm_aclWhereClause', [$this, 'aclGroupContactsOnly']);
+ unset(Civi::$statics['CRM_ACL_API']['group_permission']);
+ $rows = $this->callAPISuccess('report_template', 'getrows', [
+ 'report_id' => $template,
+ 'gid_value' => [$this->aclGroupId],
+ 'gid_op' => 'in',
+ 'options' => ['metadata' => ['sql']],
+ ]);
+ $this->assertNumberOfContactsInResult(1, $rows, $template);
+ }
+
/**
* Assert the included results match the expected.
*
\Civi::service('sql_triggers')->rebuild(NULL, TRUE);
}
+ /**
+ * 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 aclGroupOnly($type, $contactID, $tableName, $allGroups, &$ids) {
+ $ids = [$this->aclGroupId];
+ }
+
+ /**
+ * Implements hook to limit to contacts only in the aclGroup
+ *
+ * @param string $type
+ * @param array $tables
+ * @param array $whereTables
+ * @param int|null $contactID
+ * @param string $where
+ */
+ public function aclGroupContactsOnly($type, &$tables, &$whereTables, &$contactID, &$where) {
+ if (!empty($where)) {
+ $where .= ' AND ';
+ }
+ $where .= 'contact_a.id IN (SELECT contact_id FROM civicrm_group_contact WHERE status = \'Added\' AND group_id = ' . $this->aclGroupId . ')';
+ }
+
}