From: Tim Otten Date: Fri, 4 Dec 2020 07:34:44 +0000 (-0800) Subject: APIv4 - Add "Permission.get" for browsing available permissions. X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=2954197781fab7becf2b09595ac86cb6d61fea71;p=civicrm-core.git APIv4 - Add "Permission.get" for browsing available permissions. --- diff --git a/CRM/Core/Permission/List.php b/CRM/Core/Permission/List.php new file mode 100644 index 0000000000..d23ad5091c --- /dev/null +++ b/CRM/Core/Permission/List.php @@ -0,0 +1,99 @@ + $corePerm) { + $e->permissions[$permName] = [ + 'group' => 'civicrm', + 'title' => $corePerm['label'] ?? $corePerm[0] ?? $permName, + 'description' => $corePerm['description'] ?? $corePerm[1] ?? NULL, + 'is_active' => isset($activeCorePerms[$permName]), + ]; + } + } + + /** + * Enumerate permissions that originate in the CMS (core or module/plugin), + * excluding any Civi permissions. + * + * @param \Civi\Core\Event\GenericHookEvent $e + * @see \CRM_Utils_Hook::permissionList + */ + public static function findCmsPermissions(GenericHookEvent $e) { + $config = \CRM_Core_Config::singleton(); + + $ufPerms = $config->userPermissionClass->getAvailablePermissions(); + foreach ($ufPerms as $permName => $cmsPerm) { + $e->permissions[$permName] = [ + 'group' => 'cms', + 'title' => $cmsPerm['title'] ?? $permName, + 'description' => $cmsPerm['description'] ?? NULL, + ]; + } + + // There are a handful of special permissions defined in CRM/Core/Permission/*.php + // using the `translatePermission()` mechanism. + $e->permissions['cms:view user account'] = [ + 'group' => 'cms', + 'title' => ts('CMS') . ': ' . ts('View user accounts'), + 'description' => ts('View user accounts. (Synthetic permission - adapts to local CMS)'), + 'is_synthetic' => TRUE, + ]; + $e->permissions['cms:administer users'] = [ + 'group' => 'cms', + 'title' => ts('CMS') . ': ' . ts('Administer user accounts'), + 'description' => ts('Administer user accounts. (Synthetic permission - adapts to local CMS)'), + 'is_synthetic' => TRUE, + ]; + } + + /** + * @param \Civi\Core\Event\GenericHookEvent $e + * @see \CRM_Utils_Hook::permissionList + */ + public static function findConstPermissions(GenericHookEvent $e) { + // There are a handful of special permissions defined in CRM/Core/Permission. + $e->permissions[\CRM_Core_Permission::ALWAYS_DENY_PERMISSION] = [ + 'group' => 'const', + 'title' => ts('Constant: Always deny'), + 'is_synthetic' => TRUE, + ]; + $e->permissions[\CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION] = [ + 'group' => 'const', + 'title' => ts('Constant: Always allow'), + 'is_synthetic' => TRUE, + ]; + } + +} diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index f173abac3b..388145cc73 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -2000,7 +2000,7 @@ abstract class CRM_Utils_Hook { } /** - * This hook is called when loading CMS permissions; use this hook to modify + * This hook is called when exporting Civi's permission to the CMS. Use this hook to modify * the array of system permissions for CiviCRM. * * @param array $permissions @@ -2017,6 +2017,31 @@ abstract class CRM_Utils_Hook { ); } + /** + * This hook is used to enumerate the list of available permissions. It may + * include concrete permissions defined by Civi, concrete permissions defined + * by the CMS, and/or synthetic permissions. + * + * @param array $permissions + * Array of permissions, keyed by symbolic name. Each is an array with fields: + * - group: string (ex: "civicrm", "cms") + * - title: string (ex: "CiviEvent: Register for events") + * - description: string (ex: "Register for events online") + * - is_synthetic: bool (TRUE for synthetic permissions with a bespoke evaluation. FALSE for concrete permissions that registered+granted in the UF user-management layer. + * Default TRUE iff name begins with '@') + * - is_active: bool (TRUE if this permission is defined by. Default: TRUE) + * + * @return null + * The return value is ignored + * @see Civi\Api4\Permission::get() + */ + public static function permissionList(&$permissions) { + return self::singleton()->invoke(['permissions'], $permissions, + self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, + 'civicrm_permissionList' + ); + } + /** * This hook is called when checking permissions; use this hook to dynamically * escalate user permissions in certain use cases (cf. CRM-19256). diff --git a/Civi/Api4/Action/Permission/Get.php b/Civi/Api4/Action/Permission/Get.php new file mode 100644 index 0000000000..7bb0afbe72 --- /dev/null +++ b/Civi/Api4/Action/Permission/Get.php @@ -0,0 +1,52 @@ + $permName, + 'group' => 'unknown', + 'is_synthetic' => ($permName[0] === '@'), + 'is_active' => TRUE, + ]; + $perms[$permName] = array_merge($defaults, $perms[$permName]); + } + \Civi::$statics[__CLASS__][$cacheKey] = $perms; + } + + return \Civi::$statics[__CLASS__][$cacheKey]; + } + +} diff --git a/Civi/Api4/Permission.php b/Civi/Api4/Permission.php new file mode 100644 index 0000000000..8f5f3e5fdd --- /dev/null +++ b/Civi/Api4/Permission.php @@ -0,0 +1,100 @@ +setCheckPermissions($checkPermissions); + } + + /** + * @param bool $checkPermissions + * @return Generic\BasicGetFieldsAction + */ + public static function getFields($checkPermissions = TRUE) { + return (new Generic\BasicGetFieldsAction(__CLASS__, __FUNCTION__, function() { + return [ + [ + 'name' => 'group', + 'title' => 'Group', + 'required' => TRUE, + 'data_type' => 'String', + ], + [ + 'name' => 'name', + 'title' => 'Name', + 'required' => TRUE, + 'data_type' => 'String', + ], + [ + 'name' => 'title', + 'title' => 'Title', + 'required' => TRUE, + 'data_type' => 'String', + ], + [ + 'name' => 'description', + 'title' => 'Description', + 'required' => FALSE, + 'data_type' => 'String', + ], + [ + 'name' => 'is_synthetic', + 'title' => 'Is Synthetic', + 'required' => FALSE, + 'data_type' => 'Boolean', + ], + [ + 'name' => 'is_active', + 'title' => 'Is Active', + 'description' => '', + 'default' => TRUE, + 'required' => FALSE, + 'data_type' => 'Boolean', + ], + ]; + }))->setCheckPermissions($checkPermissions); + } + + /** + * @return array + */ + public static function permissions() { + return [ + "meta" => ["access CiviCRM"], + "default" => ["access CiviCRM"], + ]; + } + +} diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 28b210e2b0..4f38b4e3a2 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -366,6 +366,10 @@ class Container { $dispatcher->addListener('hook_civicrm_coreResourceList', ['\CRM_Utils_System', 'appendCoreResources']); $dispatcher->addListener('hook_civicrm_getAssetUrl', ['\CRM_Utils_System', 'alterAssetUrl']); $dispatcher->addListener('hook_civicrm_alterExternUrl', ['\CRM_Utils_System', 'migrateExternUrl'], 1000); + $dispatcher->addListener('hook_civicrm_permissionList', ['CRM_Core_Permission_List', 'findConstPermissions'], 975); + $dispatcher->addListener('hook_civicrm_permissionList', ['CRM_Core_Permission_List', 'findCiviPermissions'], 950); + $dispatcher->addListener('hook_civicrm_permissionList', ['CRM_Core_Permission_List', 'findCmsPermissions'], 925); + $dispatcher->addListener('hook_civicrm_triggerInfo', ['\CRM_Contact_BAO_RelationshipCache', 'onHookTriggerInfo']); $dispatcher->addListener('civi.dao.postInsert', ['\CRM_Core_BAO_RecurringEntity', 'triggerInsert']); $dispatcher->addListener('civi.dao.postUpdate', ['\CRM_Core_BAO_RecurringEntity', 'triggerUpdate']);