From 58c2cee91a5280a754f3511bfaa3a90716a59553 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 2 Jun 2022 10:26:30 -0400 Subject: [PATCH] SearchKit - Add "administer SearchKit" permission This permission allows non-admins to use search kit. Previously the user needed 'administer CiviCRM data' permission. Fixes dev/core#3457 --- .../CRM/Search/BAO/SearchDisplay.php | 4 +- .../SearchDisplay/AbstractRunAction.php | 7 ++- .../Api4/Action/SearchDisplay/GetDefault.php | 7 ++- .../Event/Subscriber/SearchKitSubscriber.php | 49 +++++++++++++++++++ ext/search_kit/Civi/Api4/SearchDisplay.php | 2 +- ext/search_kit/Civi/Api4/SearchSegment.php | 6 +++ ext/search_kit/search_kit.php | 14 ++++++ .../api/v4/SearchDisplay/SearchRunTest.php | 2 +- ext/search_kit/xml/Menu/search_kit.xml | 2 +- 9 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 ext/search_kit/Civi/Api4/Event/Subscriber/SearchKitSubscriber.php diff --git a/ext/search_kit/CRM/Search/BAO/SearchDisplay.php b/ext/search_kit/CRM/Search/BAO/SearchDisplay.php index 48776d96eb..c52b411427 100644 --- a/ext/search_kit/CRM/Search/BAO/SearchDisplay.php +++ b/ext/search_kit/CRM/Search/BAO/SearchDisplay.php @@ -25,8 +25,8 @@ class CRM_Search_BAO_SearchDisplay extends CRM_Search_DAO_SearchDisplay { */ public static function _checkAccess(string $entityName, string $action, array $record, int $userCID) { // If we hit this function at all, the user is not a super-admin - // But they must be at least a regular administrator - if (!CRM_Core_Permission::check('administer CiviCRM data')) { + // But they must be at least a SearchKit administrator + if (!CRM_Core_Permission::check([['administer CiviCRM data', 'administer search_kit']])) { return FALSE; } if (in_array($action, ['create', 'update'], TRUE)) { diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php index 7a60d61ffe..aaf693fb9d 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php @@ -90,8 +90,11 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction { * @throws \API_Exception */ public function _run(\Civi\Api4\Generic\Result $result) { - // Only administrators can use this in unsecured "preview mode" - if ((is_array($this->savedSearch) || is_array($this->display)) && $this->checkPermissions && !\CRM_Core_Permission::check('administer CiviCRM data')) { + // Only SearchKit admins can use this in unsecured "preview mode" + if ( + (is_array($this->savedSearch) || is_array($this->display)) && $this->checkPermissions && + !\CRM_Core_Permission::check([['administer CiviCRM data', 'administer search_kit']]) + ) { throw new UnauthorizedException('Access denied'); } $this->loadSavedSearch(); diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/GetDefault.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/GetDefault.php index 320831b7ac..9ae2d8ad6d 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/GetDefault.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/GetDefault.php @@ -42,8 +42,11 @@ class GetDefault extends \Civi\Api4\Generic\AbstractAction { * @throws \API_Exception */ public function _run(\Civi\Api4\Generic\Result $result) { - // Only administrators can use this in unsecured "preview mode" - if (is_array($this->savedSearch) && $this->checkPermissions && !\CRM_Core_Permission::check('administer CiviCRM data')) { + // Only SearchKit admins can use this in unsecured "preview mode" + if ( + is_array($this->savedSearch) && $this->checkPermissions && + !\CRM_Core_Permission::check([['administer CiviCRM data', 'administer search_kit']]) + ) { throw new UnauthorizedException('Access denied'); } $this->loadSavedSearch(); diff --git a/ext/search_kit/Civi/Api4/Event/Subscriber/SearchKitSubscriber.php b/ext/search_kit/Civi/Api4/Event/Subscriber/SearchKitSubscriber.php new file mode 100644 index 0000000000..62e4815f1c --- /dev/null +++ b/ext/search_kit/Civi/Api4/Event/Subscriber/SearchKitSubscriber.php @@ -0,0 +1,49 @@ + [ + ['onApiAuthorize', -200], + ], + ]; + } + + /** + * Alters APIv4 permissions to allow users with 'administer search_kit' to create/delete a SavedSearch + * + * @param \Civi\API\Event\AuthorizeEvent $event + * API authorization event. + */ + public function onApiAuthorize(\Civi\API\Event\AuthorizeEvent $event) { + /* @var \Civi\Api4\Generic\AbstractAction $apiRequest */ + $apiRequest = $event->getApiRequest(); + if ($apiRequest['version'] == 4 && $apiRequest->getEntityName() === 'SavedSearch') { + if (\CRM_Core_Permission::check('administer search_kit')) { + $event->authorize(); + $event->stopPropagation(); + } + } + } + +} diff --git a/ext/search_kit/Civi/Api4/SearchDisplay.php b/ext/search_kit/Civi/Api4/SearchDisplay.php index 58e37d483c..f748b72304 100644 --- a/ext/search_kit/Civi/Api4/SearchDisplay.php +++ b/ext/search_kit/Civi/Api4/SearchDisplay.php @@ -51,7 +51,7 @@ class SearchDisplay extends Generic\DAOEntity { public static function permissions() { $permissions = parent::permissions(); - $permissions['default'] = ['administer CiviCRM data']; + $permissions['default'] = [['administer CiviCRM data', 'administer search_kit']]; // Anyone with access to CiviCRM can view search displays (but not necessarily the results) $permissions['get'] = $permissions['getDefault'] = ['access CiviCRM']; // Anyone with access to CiviCRM can do search tasks (but not necessarily all of them) diff --git a/ext/search_kit/Civi/Api4/SearchSegment.php b/ext/search_kit/Civi/Api4/SearchSegment.php index 15df9c4d8a..3b44620e7a 100644 --- a/ext/search_kit/Civi/Api4/SearchSegment.php +++ b/ext/search_kit/Civi/Api4/SearchSegment.php @@ -9,4 +9,10 @@ namespace Civi\Api4; class SearchSegment extends Generic\DAOEntity { use \Civi\Api4\Generic\Traits\ManagedEntity; + public static function permissions() { + $permissions = parent::permissions(); + $permissions['default'] = [['administer CiviCRM data', 'administer search_kit']]; + return $permissions; + } + } diff --git a/ext/search_kit/search_kit.php b/ext/search_kit/search_kit.php index bf742583e3..54e23a17f6 100644 --- a/ext/search_kit/search_kit.php +++ b/ext/search_kit/search_kit.php @@ -1,6 +1,7 @@ addListener('hook_civicrm_alterAngular', ['\Civi\Search\AfformSearchMetadataInjector', 'preprocess'], 1000); + Civi::dispatcher()->addSubscriber(new Civi\Api4\Event\Subscriber\SearchKitSubscriber()); } /** @@ -23,6 +25,18 @@ function search_kit_civicrm_container($container) { ]); } +/** + * Implements hook_civicrm_permission(). + * + * Define SearchKit permissions. + */ +function search_kit_civicrm_permission(&$permissions) { + $permissions['administer search_kit'] = [ + E::ts('Search Kit: edit and delete searches'), + E::ts('Gives non-admin users access to the Search Kit UI to create, update and delete searches and displays'), + ]; +} + /** * Implements hook_civicrm_alterApiRoutePermissions(). * diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php index 62e43010b0..e0ce60a62e 100644 --- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -712,7 +712,7 @@ class SearchRunTest extends \PHPUnit\Framework\TestCase implements HeadlessInter } $this->assertStringContainsString('failed', $error); - $config->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM data']; + $config->userPermissionClass->permissions = ['access CiviCRM', 'administer search_kit']; // Admins can edit the search and the display SavedSearch::update()->addWhere('name', '=', $searchName) diff --git a/ext/search_kit/xml/Menu/search_kit.xml b/ext/search_kit/xml/Menu/search_kit.xml index eb53c32709..9a641dcf73 100644 --- a/ext/search_kit/xml/Menu/search_kit.xml +++ b/ext/search_kit/xml/Menu/search_kit.xml @@ -8,6 +8,6 @@ civicrm/admin/search CRM_Search_Page_Admin - administer CiviCRM data + administer CiviCRM data;administer search_kit -- 2.25.1