For unknown historical reasons, group-based ACLs incorrectly used 'civicrm_saved_search'
as the value for 'object_table' when referencing a group id.
This updates all ACL records, tests, and adds legacy handling for hook subscribers with a noisy deprecation notice.
public static function group(
$type,
$contactID = NULL,
- $tableName = 'civicrm_saved_search',
+ $tableName = 'civicrm_group',
$allGroups = NULL,
$includedGroups = []
) {
$type,
$groupID,
$contactID = NULL,
- $tableName = 'civicrm_saved_search',
+ $tableName = 'civicrm_group',
$allGroups = NULL,
$includedGroups = NULL
) {
FROM civicrm_acl_cache c, civicrm_acl a
WHERE c.acl_id = a.id
AND a.is_active = 1
- AND a.object_table = 'civicrm_saved_search'
+ AND a.object_table = 'civicrm_group'
AND a.id IN ( $aclKeys )
AND a.deny = 0
ORDER BY a.object_id
FROM civicrm_acl_cache c, civicrm_acl a
WHERE c.acl_id = a.id
AND a.is_active = 1
- AND a.object_table = 'civicrm_saved_search'
+ AND a.object_table = 'civicrm_group'
AND a.id IN ( $aclKeys )
AND a.deny = 1
AND a.object_id IN (%1)
public static function group(
$type,
$contactID = NULL,
- $tableName = 'civicrm_saved_search',
+ $tableName = 'civicrm_group',
$allGroups = NULL,
$includedGroups = []
) {
if (isset($defaults['object_table'])) {
switch ($defaults['object_table']) {
- case 'civicrm_saved_search':
+ case 'civicrm_group':
$defaults['group_id'] = $defaults['object_id'];
$defaults['object_type'] = 1;
$showHide->addShow("id-group-acl");
// Figure out which type of object we're permissioning on and set object_table and object_id.
switch ($params['object_type']) {
case 1:
- $params['object_table'] = 'civicrm_saved_search';
+ $params['object_table'] = 'civicrm_group';
$params['object_id'] = $params['group_id'];
break;
}
switch ($acl[$dao->id]['object_table']) {
- case 'civicrm_saved_search':
+ case 'civicrm_group':
$acl[$dao->id]['object'] = $group[$acl[$dao->id]['object_id']] ?? NULL;
$acl[$dao->id]['object_name'] = ts('Group');
break;
public static function updateCiviACL(&$params, $op) {
$dao = new CRM_ACL_DAO_ACL();
- $dao->object_table = 'civicrm_saved_search';
+ $dao->object_table = 'civicrm_group';
$dao->object_id = $params['civicrm_group_id'];
if ($op == 'delete') {
$permissions = NULL;
if (CRM_Core_Permission::check('edit all contacts') ||
CRM_ACL_API::groupPermission(CRM_ACL_API::EDIT, $id, NULL,
- 'civicrm_saved_search', $allGroups
+ 'civicrm_group', $allGroups
)
) {
$permissions[] = CRM_Core_Permission::EDIT;
if (CRM_Core_Permission::check('view all contacts') ||
CRM_ACL_API::groupPermission(CRM_ACL_API::VIEW, $id, NULL,
- 'civicrm_saved_search', $allGroups
+ 'civicrm_group', $allGroups
)
) {
$permissions[] = CRM_Core_Permission::VIEW;
$clauses = [];
if (!CRM_Core_Permission::check([['edit all contacts', 'view all contacts']])) {
$allGroups = CRM_Core_PseudoConstant::allGroup(NULL, FALSE);
- // FIXME: TableName 'civicrm_saved_search' seems wrong but is consistent with self::checkPermission
- $allowedGroups = \CRM_ACL_API::group(CRM_ACL_API::VIEW, NULL, 'civicrm_saved_search', $allGroups);
+ $allowedGroups = \CRM_ACL_API::group(CRM_ACL_API::VIEW, NULL, 'civicrm_group', $allGroups);
$groupsIn = $allowedGroups ? implode(',', $allowedGroups) : '0';
$clauses['id'][] = "IN ($groupsIn)";
}
Civi::$statics[__CLASS__]['viewPermissionedGroups_' . $domainId . '_' . $userId][$groupKey] = $groups;
}
- $ids = CRM_ACL_API::group(CRM_Core_Permission::VIEW, NULL, 'civicrm_saved_search', $groups);
+ $ids = CRM_ACL_API::group(CRM_Core_Permission::VIEW, NULL, 'civicrm_group', $groups);
if (!empty($ids)) {
foreach (array_values($ids) as $id) {
$title = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $id, 'title');
}
}
- $ids = CRM_ACL_API::group(CRM_Core_Permission::EDIT, NULL, 'civicrm_saved_search', $groups);
+ $ids = CRM_ACL_API::group(CRM_Core_Permission::EDIT, NULL, 'civicrm_group', $groups);
if (!empty($ids)) {
foreach (array_values($ids) as $id) {
$title = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $id, 'title');
-- Remove obsolete "Basic ACLs"
DELETE FROM civicrm_acl
-WHERE object_table NOT IN ('civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group', 'civicrm_event');
+WHERE object_table NOT IN ('civicrm_group', 'civicrm_saved_search', 'civicrm_uf_group', 'civicrm_custom_group', 'civicrm_event');
+
+-- Fix wrong table name
+UPDATE `civicrm_acl` SET `object_table` = 'civicrm_group' WHERE `object_table` = 'civicrm_saved_search';
-- fix mis-casing of field name. Note the php function doesn't permit the name change hence it is here
-- but field is not localised.
* @param int $contactID
* User contactID for whom the check is made.
* @param string $tableName
- * Table name of group, e.g. `civicrm_uf_group` or `civicrm_custom_group`.
- * Note: for some weird reason when this hook is called for contact groups, this
- * value will be `civicrm_saved_search` instead of `civicrm_group` as you'd expect.
+ * Table name of group, e.g. 'civicrm_group' or 'civicrm_uf_group' or 'civicrm_custom_group'.
* @param array $allGroups
* All groups from the above table, keyed by id.
* @param int[] $currentGroups
*/
public static function aclGroup($type, $contactID, $tableName, &$allGroups, &$currentGroups) {
$null = NULL;
+ // Legacy support for hooks that still expect 'civicrm_group' to be 'civicrm_saved_search'
+ // This was changed in 5.64
+ if ($tableName === 'civicrm_group') {
+ $initialValue = $currentGroups;
+ $legacyTableName = 'civicrm_saved_search';
+ self::singleton()
+ ->invoke(['type', 'contactID', 'tableName', 'allGroups', 'currentGroups'], $type, $contactID, $legacyTableName, $allGroups, $currentGroups, $null, 'civicrm_aclGroup');
+ if ($initialValue != $currentGroups) {
+ CRM_Core_Error::deprecatedWarning('Since 5.64 hook_civicrm_aclGroup passes "civicrm_group" instead of "civicrm_saved_search" for the $tableName when referring to Groups. Hook listeners should be updated.');
+ }
+ }
return self::singleton()
->invoke(['type', 'contactID', 'tableName', 'allGroups', 'currentGroups'], $type, $contactID, $tableName, $allGroups, $currentGroups, $null, 'civicrm_aclGroup');
}
* @throws CRM_Core_Exception
*/
public function setupCoreACLPermittedAcl($permissionedEntities = [], $groupAllowedAccess = 'Everyone', $operation = 'View', $entity = 'Group') {
- $tableMap = ['Group' => 'civicrm_saved_search', 'CustomGroup' => 'civicrm_custom_group', 'Profile' => 'civicrm_uf_match', 'Event' => 'civicrm_event'];
+ $tableMap = ['Group' => 'civicrm_group', 'CustomGroup' => 'civicrm_custom_group', 'Profile' => 'civicrm_uf_group', 'Event' => 'civicrm_event'];
$entityTable = $tableMap[$entity];
$permittedRoleID = ($groupAllowedAccess === 'Everyone') ? 0 : $groupAllowedAccess;
* @param array $currentGroups
*/
public function hook_civicrm_aclGroup($type, $contactID, $tableName, &$allGroups, &$currentGroups) {
+ if ($tableName !== 'civicrm_group') {
+ return;
+ }
//don't use api - you will get a loop
$sql = " SELECT * FROM civicrm_group WHERE name LIKE '%pick%'";
$groups = [];
`name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
)
VALUES (
- 'core-580', 'civicrm_acl_role', 55, 'Edit', 'civicrm_saved_search', 0, 1
+ 'core-580', 'civicrm_acl_role', 55, 'Edit', 'civicrm_group', 0, 1
);
");
* @param array $currentGroups
*/
public function hook_civicrm_aclGroup($type, $contactID, $tableName, &$allGroups, &$currentGroups) {
+ if ($tableName !== 'civicrm_group') {
+ return;
+ }
//don't use api - you will get a loop
$sql = " SELECT * FROM civicrm_group";
$groups = [];
`name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
)
VALUES (
- 'view picked', 'civicrm_group', $this->_permissionedGroup , 'Edit', 'civicrm_saved_search', {$this->_permissionedGroup}, 1
+ 'view picked', 'civicrm_group', $this->_permissionedGroup , 'Edit', 'civicrm_group', {$this->_permissionedGroup}, 1
);
");
`name`, `entity_table`, `entity_id`, `operation`, `object_table`, `object_id`, `is_active`
)
VALUES (
- 'view picked', 'civicrm_group', $this->_permissionedGroup, 'Edit', 'civicrm_saved_search', {$this->_permissionedDisabledGroup}, 1
+ 'view picked', 'civicrm_group', $this->_permissionedGroup, 'Edit', 'civicrm_group', {$this->_permissionedDisabledGroup}, 1
);
");
}
* @param array $ids
*/
public function aclGroupAllGroups($type, $contactID, $tableName, $allGroups, &$ids) {
- $group = $this->callAPISuccess('Group', 'get', ['name' => 'Test Group 1']);
- $ids = array_keys($group['values']);
+ if ($tableName === 'civicrm_group') {
+ $group = $this->callAPISuccess('Group', 'get', ['name' => 'Test Group 1']);
+ $ids = array_keys($group['values']);
+ }
}
}
* this from civicrm_generated.mysql
*/
private function setUpACLByCheating() {
- CRM_Core_DAO::executeQuery("INSERT INTO civicrm_acl (name, deny, entity_table, entity_id, operation, object_table, object_id, acl_table, acl_id, is_active) VALUES ('Edit All Contacts', 0, 'civicrm_acl_role', 1, 'Edit', 'civicrm_saved_search', 0, NULL, NULL, 1)");
- CRM_Core_DAO::executeQuery("INSERT INTO civicrm_acl (name, deny, entity_table, entity_id, operation, object_table, object_id, acl_table, acl_id, is_active) VALUES ('Core ACL',0,'civicrm_acl_role',0,'All','access CiviMail subscribe/unsubscribe pages',NULL,NULL,NULL,1)");
+ CRM_Core_DAO::executeQuery("INSERT INTO civicrm_acl (name, deny, entity_table, entity_id, operation, object_table, object_id, acl_table, acl_id, is_active) VALUES ('Edit All Contacts', 0, 'civicrm_acl_role', 1, 'Edit', 'civicrm_group', 0, NULL, NULL, 1)");
}
}
* @param array $ids
*/
public function aclGroupOnly($type, $contactID, $tableName, $allGroups, &$ids) {
- $ids = [$this->aclGroupID];
+ if ($tableName === 'civicrm_group') {
+ $ids = [$this->aclGroupID];
+ }
}
/**
-- Create ACL to edit and view contacts in all groups
INSERT INTO civicrm_acl (name, deny, entity_table, entity_id, operation, object_table, object_id, acl_table, acl_id, is_active, priority)
VALUES
-('Edit All Contacts', 0, 'civicrm_acl_role', 1, 'Edit', 'civicrm_saved_search', 0, NULL, NULL, 1, 1);
+('Edit All Contacts', 0, 'civicrm_acl_role', 1, 'Edit', 'civicrm_group', 0, NULL, NULL, 1, 1);
-- Create default Groups for User Permissioning
INSERT INTO civicrm_group (`id`, `name`, `title`, `description`, `source`, `saved_search_id`, `is_active`, `visibility`, `group_type`)