if (!$actionName) {
return FALSE;
}
+ if ($actionName === 'create') {
+ // No record to check for this action and getPermittedLinkAction says it's allowed; we're good.
+ return TRUE;
+ }
$idField = CoreUtil::getIdFieldName($link['entity']);
$idKey = $this->getIdKeyName($link['entity']);
$id = $data[$link['prefix'] . $idKey] ?? NULL;
$apiRequest = Request::create($link['entity'], $actionName, ['version' => 4]);
return CoreUtil::checkAccessRecord($apiRequest, $values);
}
+ // No id so cannot possibly update or delete record
+ return FALSE;
}
return TRUE;
}
'allowed' => civicrm_api4($entityName, 'getActions', ['checkPermissions' => TRUE])->column('name'),
];
}
+ // Map CRM_Core_Action names to API action names :/
+ $map = [
+ 'add' => 'create',
+ ];
+ $actionName = $map[$actionName] ?? $actionName;
// Action exists and is permitted
if (in_array($actionName, $this->entityActions[$entityName]['allowed'], TRUE)) {
return $actionName;
* @param array $data
* @return bool
*/
- private function checkLinkCondition(array $item, array $data): bool {
+ protected function checkLinkCondition(array $item, array $data): bool {
if (empty($item['condition'][0]) || empty($item['condition'][1])) {
return TRUE;
}
$op = $item['condition'][1];
if ($item['condition'][0] === 'check user permission') {
- if (!empty($item['condition'][2]) && !\CRM_Core_Permission::check($item['condition'][2])) {
- return $op !== '=';
+ // No permission == open access
+ if (empty($item['condition'][2])) {
+ return TRUE;
}
- return TRUE;
+ $permissions = (array) $item['condition'][2];
+ if ($op === 'CONTAINS') {
+ // Place conditions in OR array for CONTAINS operator
+ $permissions = [$permissions];
+ }
+ return \CRM_Core_Permission::check($permissions) == ($op !== '!=');
}
// Convert the conditional value of 'current_domain' into an actual value that filterCompare can work with
if ($item['condition'][2] === 'current_domain') {
$settings['toolbar'][] = $settings['addButton'] + ['style' => 'primary', 'target' => 'crm-popup'];
}
foreach ($settings['toolbar'] ?? [] as $button) {
+ if (!$this->checkLinkCondition($button, $data)) {
+ continue;
+ }
$button = $this->formatLink($button, $data);
if ($button) {
$toolbar[] = $button;
linkProps = ['path', 'task', 'entity', 'action', 'join', 'target', 'icon', 'text', 'style', 'condition'];
ctrl.permissionOperators = [
- {key: '=', value: ts('Has')},
- {key: '!=', value: ts('Lacks')}
+ {key: 'CONTAINS', value: ts('Includes')},
+ {key: '=', value: ts('Has All')},
+ {key: '!=', value: ts('Lacks All')}
];
this.styles = CRM.crmSearchAdmin.styles;
<input ng-model="item.condition[0]" crm-ui-select="{placeholder: item.action ? ts('Allowed') : ts('Always'), data: $ctrl.fields}" ng-change="$ctrl.onChangeCondition(item)">
<div class="form-group" ng-if="item.condition[0] === 'check user permission'">
<select class="form-control api4-operator" ng-model="item.condition[1]" ng-options="o.key as o.value for o in $ctrl.permissionOperators"></select>
- <input class="form-control" crm-ui-select="{data: $ctrl.permissions}" ng-model="item.condition[2]">
+ <input class="form-control" crm-ui-select="{data: $ctrl.permissions, multiple: true}" ng-model="item.condition[2]" ng-list>
</div>
<crm-search-condition class="form-group"
ng-if="item.condition[0] && item.condition[0] !== 'check user permission'"
public function testRunWithToolbar(): void {
$params = [
- 'checkPermissions' => FALSE,
'return' => 'page:1',
'savedSearch' => [
'api_entity' => 'Contact',
],
'filters' => ['contact_type' => 'Individual'],
];
+ // No 'add contacts' permission == no "Add contacts" button
+ \CRM_Core_Config::singleton()->userPermissionClass->permissions = [
+ 'access CiviCRM',
+ 'administer search_kit',
+ ];
+ $result = civicrm_api4('SearchDisplay', 'run', $params);
+ $this->assertCount(0, $result->toolbar);
+ // With 'add contacts' permission the button will be shown
+ \CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'add contacts';
$result = civicrm_api4('SearchDisplay', 'run', $params);
$this->assertCount(1, $result->toolbar);
$button = $result->toolbar[0];
$this->assertTrue($button['autoOpen']);
}
+ public static function toolbarLinkPermissions(): array {
+ $sets = [];
+ $sets[] = [
+ 'CONTAINS',
+ ['access CiviCRM', 'administer CiviCRM'],
+ ['access CiviCRM'],
+ TRUE,
+ ];
+ $sets[] = [
+ '=',
+ ['access CiviCRM', 'administer CiviCRM'],
+ ['access CiviCRM'],
+ FALSE,
+ ];
+ $sets[] = [
+ '!=',
+ ['access CiviCRM', 'administer CiviCRM'],
+ ['access CiviCRM'],
+ TRUE,
+ ];
+ $sets[] = [
+ 'CONTAINS',
+ ['access CiviCRM', 'administer CiviCRM'],
+ [],
+ FALSE,
+ ];
+ $sets[] = [
+ '=',
+ [],
+ [],
+ TRUE,
+ ];
+ return $sets;
+ }
+
+ /**
+ * @dataProvider toolbarLinkPermissions
+ */
+ public function testToolbarLinksPermissionOperators($linkOperator, $linkPerms, $userPerms, $shouldBeVisible): void {
+ $params = [
+ 'return' => 'page:1',
+ 'savedSearch' => [
+ 'api_entity' => 'Contact',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => ['first_name', 'contact_type'],
+ ],
+ ],
+ 'display' => [
+ 'type' => 'table',
+ 'label' => '',
+ 'settings' => [
+ 'actions' => TRUE,
+ 'pager' => [],
+ 'toolbar' => [
+ [
+ 'path' => 'civicrm/test',
+ 'text' => 'Test',
+ 'condition' => [
+ 'check user permission',
+ $linkOperator,
+ $linkPerms,
+ ],
+ ],
+ ],
+ 'columns' => [],
+ ],
+ ],
+ ];
+ \CRM_Core_Config::singleton()->userPermissionClass->permissions = array_merge(['administer search_kit'], $userPerms);
+ $result = civicrm_api4('SearchDisplay', 'run', $params);
+ $this->assertCount((int) $shouldBeVisible, $result->toolbar);
+ }
+
public function testRunWithEntityFile(): void {
$cid = $this->createTestRecord('Contact')['id'];
$notes = $this->saveTestRecords('Note', [