* TRUE if granted. FALSE if prohibited. NULL if indeterminate.
*/
public static function _checkAccess(string $entityName, string $action, array $record, int $userID): ?bool {
+ // This check implements two rules: you must have access to the specific custom-data-group - and to the underlying record (e.g. Contact).
+
$groupName = substr($entityName, 0, 7) === 'Custom_' ? substr($entityName, 7) : NULL;
+ $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name');
+ $id = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'id', 'name');
if (!$groupName) {
// $groupName is required but the function signature has to match the parent.
- throw new CRM_Core_Exception('Missing required $groupName in CustomValue::checkAccess');
+ throw new CRM_Core_Exception('Missing required group-name in CustomValue::checkAccess');
}
- // Currently, multi-record custom data always extends Contacts
- $extends = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'extends', 'name');
- if (!in_array($extends, ['Contact', 'Individual', 'Organization', 'Household'])) {
- throw new CRM_Core_Exception("Cannot assess delegated permissions for group {$groupName}.");
+
+ if (empty($extends) || empty($id)) {
+ throw new CRM_Core_Exception('Received invalid group-name in CustomValue::checkAccess');
}
- $cid = $record['entity_id'] ?? NULL;
- if (!$cid) {
+ $customGroups = [$id => $id];
+ $defaultGroups = CRM_Core_Permission::customGroupAdmin() ? [$id] : [];
+ // FIXME: Per current onscreen help (Admin=>ACLs=>Add ACLs), CustomGroup ACLs treat VIEW and EDIT as the same. Skimming code, it appears that existing checks use VIEW.
+ $accessList = CRM_ACL_API::group(CRM_Core_Permission::VIEW, $userID, 'civicrm_custom_group', $customGroups, $defaultGroups);
+ if (empty($accessList)) {
+ return FALSE;
+ }
+
+ $eid = $record['entity_id'] ?? NULL;
+ if (!$eid) {
$tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $groupName, 'table_name', 'name');
- $cid = CRM_Core_DAO::singleValueQuery("SELECT entity_id FROM `$tableName` WHERE id = " . (int) $record['id']);
+ $eid = CRM_Core_DAO::singleValueQuery("SELECT entity_id FROM `$tableName` WHERE id = " . (int) $record['id']);
}
- return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated('Contact', 'update', ['id' => $cid], $userID);
+ // Do we have access to the target record?
+ if (in_array($extends, ['Contact', 'Individual', 'Organization', 'Household'])) {
+ return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated('Contact', 'update', ['id' => $eid], $userID);
+ }
+ elseif (\Civi\Api4\Utils\CoreUtil::getApiClass($extends)) {
+ // For most entities (Activity, Relationship, Contribution, ad nauseum), we acn just use an eponymous API.
+ return \Civi\Api4\Utils\CoreUtil::checkAccessDelegated($extends, 'update', ['id' => $eid], $userID);
+ }
+ else {
+ // Do you need to add a special case for some oddball custom-group type?
+ throw new CRM_Core_Exception("Cannot assess delegated permissions for group {$groupName}.");
+ }
}
}