standalone: change schema for RBAC; update tests
authorRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Mon, 3 Jul 2023 09:57:06 +0000 (10:57 +0100)
committerRich Lott / Artful Robot <code.commits@artfulrobot.uk>
Mon, 3 Jul 2023 09:57:06 +0000 (10:57 +0100)
15 files changed:
CRM/Core/SelectValues.php
ext/standaloneusers/CRM/Standaloneusers/BAO/Role.php [new file with mode: 0644]
ext/standaloneusers/CRM/Standaloneusers/DAO/Role.php [moved from ext/standaloneusers/CRM/Standaloneusers/DAO/RolePermission.php with 54% similarity]
ext/standaloneusers/CRM/Standaloneusers/DAO/User.php
ext/standaloneusers/Civi/Api4/Role.php [moved from ext/standaloneusers/Civi/Api4/RolePermission.php with 60% similarity]
ext/standaloneusers/Civi/Standalone/Security.php
ext/standaloneusers/managed/OptionGroup_role.mgd.php [deleted file]
ext/standaloneusers/sql/auto_install.sql
ext/standaloneusers/sql/auto_uninstall.sql
ext/standaloneusers/tests/phpunit/Civi/Standalone/SecurityTest.php
ext/standaloneusers/xml/schema/CRM/Standaloneusers/Role.entityType.php [moved from ext/standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.entityType.php with 59% similarity]
ext/standaloneusers/xml/schema/CRM/Standaloneusers/Role.xml [new file with mode: 0644]
ext/standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.xml [deleted file]
ext/standaloneusers/xml/schema/CRM/Standaloneusers/User.xml
setup/plugins/init/StandaloneUsers.civi-setup.php

index 3b7c2427817efa02693e93df16e8d9b316385724..bcbff0c96db9658c9854b8676bc30690b070af06 100644 (file)
@@ -1210,4 +1210,23 @@ class CRM_Core_SelectValues {
     ];
   }
 
+  /**
+   * Callback for Role.permissions pseudoconstant values.
+   *
+   * Permissions for Civi Standalone, not used by CMS-based systems.
+   *
+   * @return array
+   */
+  public static function permissions() {
+    $perms = $options = [];
+    \CRM_Utils_Hook::permissionList($perms);
+
+    foreach ($perms as $machineName => $details) {
+      if ($details['is_active']) {
+        $options[$machineName] = $details['title'];
+      }
+    }
+    return $options;
+  }
+
 }
diff --git a/ext/standaloneusers/CRM/Standaloneusers/BAO/Role.php b/ext/standaloneusers/CRM/Standaloneusers/BAO/Role.php
new file mode 100644 (file)
index 0000000..5517aa7
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+// phpcs:disable
+use CRM_Standaloneusers_ExtensionUtil as E;
+// phpcs:enable
+
+class CRM_Standaloneusers_BAO_Role extends CRM_Standaloneusers_DAO_Role {
+
+  /**
+   * Create a new Role based on array-data
+   *
+   * @param array $params key-value pairs
+   * @return CRM_Standaloneusers_DAO_Role|NULL
+   */
+  /*
+  public static function create($params) {
+    $className = 'CRM_Standaloneusers_DAO_Role';
+    $entityName = 'Role';
+    $hook = empty($params['id']) ? 'create' : 'edit';
+
+    CRM_Utils_Hook::pre($hook, $entityName, CRM_Utils_Array::value('id', $params), $params);
+    $instance = new $className();
+    $instance->copyValues($params);
+    $instance->save();
+    CRM_Utils_Hook::post($hook, $entityName, $instance->id, $instance);
+
+    return $instance;
+  }
+  */
+
+}
similarity index 54%
rename from ext/standaloneusers/CRM/Standaloneusers/DAO/RolePermission.php
rename to ext/standaloneusers/CRM/Standaloneusers/DAO/Role.php
index fc800fb63704e9a4e5f1e170b8ee121a508b2d68..f673ef54943f644a961be6d2961251ff158ec244 100644 (file)
@@ -4,16 +4,16 @@
  * @package CRM
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  *
- * Generated from standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.xml
+ * Generated from standaloneusers/xml/schema/CRM/Standaloneusers/Role.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:9bd09dba43f645696426e1ef15f776d9)
+ * (GenCodeChecksum:d28fa09f872be30740de728c9e344a6d)
  */
 use CRM_Standaloneusers_ExtensionUtil as E;
 
 /**
- * Database access object for the RolePermission entity.
+ * Database access object for the Role entity.
  */
-class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
+class CRM_Standaloneusers_DAO_Role extends CRM_Core_DAO {
   const EXT = E::LONG_NAME;
   const TABLE_ADDED = '';
 
@@ -22,7 +22,14 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
    *
    * @var string
    */
-  public static $_tableName = 'civicrm_role_permission';
+  public static $_tableName = 'civicrm_role';
+
+  /**
+   * Field to show when displaying a record.
+   *
+   * @var string
+   */
+  public static $_labelField = 'label';
 
   /**
    * Should CiviCRM log any modifications to this table in the civicrm_log table.
@@ -32,7 +39,7 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
   public static $_log = TRUE;
 
   /**
-   * Unique RolePermission ID
+   * Unique Role ID
    *
    * @var int|string|null
    *   (SQL type: int unsigned)
@@ -41,28 +48,46 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
   public $id;
 
   /**
-   * FK to a role option value
+   * Machine name for this role
    *
-   * @var int|string|null
-   *   (SQL type: int unsigned)
+   * @var string
+   *   (SQL type: varchar(60))
    *   Note that values will be retrieved from the database as a string.
    */
-  public $role_id;
+  public $name;
 
   /**
-   * A single permission granted to this role
+   * Human friendly name for this role
    *
    * @var string
-   *   (SQL type: varchar(60))
+   *   (SQL type: varchar(128))
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $label;
+
+  /**
+   * List of permissions granted by this role
+   *
+   * @var string
+   *   (SQL type: text)
+   *   Note that values will be retrieved from the database as a string.
+   */
+  public $permissions;
+
+  /**
+   * Only active roles grant permissions
+   *
+   * @var bool|string|null
+   *   (SQL type: tinyint)
    *   Note that values will be retrieved from the database as a string.
    */
-  public $permission;
+  public $is_active;
 
   /**
    * Class constructor.
    */
   public function __construct() {
-    $this->__table = 'civicrm_role_permission';
+    $this->__table = 'civicrm_role';
     parent::__construct();
   }
 
@@ -73,7 +98,7 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
    *   Whether to return the plural version of the title.
    */
   public static function getEntityTitle($plural = FALSE) {
-    return $plural ? E::ts('Role Permissions') : E::ts('Role Permission');
+    return $plural ? E::ts('Roles') : E::ts('Role');
   }
 
   /**
@@ -88,7 +113,7 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
           'name' => 'id',
           'type' => CRM_Utils_Type::T_INT,
           'title' => E::ts('ID'),
-          'description' => E::ts('Unique RolePermission ID'),
+          'description' => E::ts('Unique Role ID'),
           'required' => TRUE,
           'usage' => [
             'import' => FALSE,
@@ -96,10 +121,10 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
             'duplicate_matching' => FALSE,
             'token' => FALSE,
           ],
-          'where' => 'civicrm_role_permission.id',
-          'table_name' => 'civicrm_role_permission',
-          'entity' => 'RolePermission',
-          'bao' => 'CRM_Standaloneusers_DAO_RolePermission',
+          'where' => 'civicrm_role.id',
+          'table_name' => 'civicrm_role',
+          'entity' => 'Role',
+          'bao' => 'CRM_Standaloneusers_DAO_Role',
           'localizable' => 0,
           'html' => [
             'type' => 'Number',
@@ -107,47 +132,94 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
           'readonly' => TRUE,
           'add' => NULL,
         ],
-        'role_id' => [
-          'name' => 'role_id',
-          'type' => CRM_Utils_Type::T_INT,
-          'title' => E::ts('Role ID'),
-          'description' => E::ts('FK to a role option value'),
+        'name' => [
+          'name' => 'name',
+          'type' => CRM_Utils_Type::T_STRING,
+          'title' => E::ts('Name'),
+          'description' => E::ts('Machine name for this role'),
+          'required' => TRUE,
+          'maxlength' => 60,
+          'size' => CRM_Utils_Type::BIG,
           'usage' => [
             'import' => FALSE,
             'export' => FALSE,
             'duplicate_matching' => FALSE,
             'token' => FALSE,
           ],
-          'where' => 'civicrm_role_permission.role_id',
-          'table_name' => 'civicrm_role_permission',
-          'entity' => 'RolePermission',
-          'bao' => 'CRM_Standaloneusers_DAO_RolePermission',
+          'where' => 'civicrm_role.name',
+          'table_name' => 'civicrm_role',
+          'entity' => 'Role',
+          'bao' => 'CRM_Standaloneusers_DAO_Role',
           'localizable' => 0,
-          'pseudoconstant' => [
-            'optionGroupName' => 'role',
-            'optionEditPath' => 'civicrm/admin/options/role',
-          ],
           'add' => NULL,
         ],
-        'permission' => [
-          'name' => 'permission',
+        'label' => [
+          'name' => 'label',
           'type' => CRM_Utils_Type::T_STRING,
-          'title' => E::ts('Permission'),
-          'description' => E::ts('A single permission granted to this role'),
+          'title' => E::ts('Label'),
+          'description' => E::ts('Human friendly name for this role'),
+          'required' => TRUE,
+          'maxlength' => 128,
+          'size' => CRM_Utils_Type::HUGE,
+          'usage' => [
+            'import' => FALSE,
+            'export' => FALSE,
+            'duplicate_matching' => FALSE,
+            'token' => FALSE,
+          ],
+          'where' => 'civicrm_role.label',
+          'table_name' => 'civicrm_role',
+          'entity' => 'Role',
+          'bao' => 'CRM_Standaloneusers_DAO_Role',
+          'localizable' => 0,
+          'add' => NULL,
+        ],
+        'permissions' => [
+          'name' => 'permissions',
+          'type' => CRM_Utils_Type::T_TEXT,
+          'title' => E::ts('Permissions'),
+          'description' => E::ts('List of permissions granted by this role'),
           'required' => TRUE,
-          'maxlength' => 60,
-          'size' => CRM_Utils_Type::BIG,
           'usage' => [
             'import' => FALSE,
             'export' => FALSE,
             'duplicate_matching' => FALSE,
             'token' => FALSE,
           ],
-          'where' => 'civicrm_role_permission.permission',
-          'table_name' => 'civicrm_role_permission',
-          'entity' => 'RolePermission',
-          'bao' => 'CRM_Standaloneusers_DAO_RolePermission',
+          'where' => 'civicrm_role.permissions',
+          'table_name' => 'civicrm_role',
+          'entity' => 'Role',
+          'bao' => 'CRM_Standaloneusers_DAO_Role',
           'localizable' => 0,
+          'serialize' => self::SERIALIZE_SEPARATOR_BOOKEND,
+          'html' => [
+            'type' => 'Select',
+          ],
+          'pseudoconstant' => [
+            'callback' => 'CRM_Core_SelectValues::permissions',
+          ],
+          'add' => NULL,
+        ],
+        'is_active' => [
+          'name' => 'is_active',
+          'type' => CRM_Utils_Type::T_BOOLEAN,
+          'title' => E::ts('Role is active'),
+          'description' => E::ts('Only active roles grant permissions'),
+          'usage' => [
+            'import' => FALSE,
+            'export' => FALSE,
+            'duplicate_matching' => FALSE,
+            'token' => FALSE,
+          ],
+          'where' => 'civicrm_role.is_active',
+          'default' => '1',
+          'table_name' => 'civicrm_role',
+          'entity' => 'Role',
+          'bao' => 'CRM_Standaloneusers_DAO_Role',
+          'localizable' => 0,
+          'html' => [
+            'type' => 'CheckBox',
+          ],
           'add' => NULL,
         ],
       ];
@@ -195,7 +267,7 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
    * @return array
    */
   public static function &import($prefix = FALSE) {
-    $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'role_permission', $prefix, []);
+    $r = CRM_Core_DAO_AllCoreTables::getImports(__CLASS__, 'role', $prefix, []);
     return $r;
   }
 
@@ -207,7 +279,7 @@ class CRM_Standaloneusers_DAO_RolePermission extends CRM_Core_DAO {
    * @return array
    */
   public static function &export($prefix = FALSE) {
-    $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'role_permission', $prefix, []);
+    $r = CRM_Core_DAO_AllCoreTables::getExports(__CLASS__, 'role', $prefix, []);
     return $r;
   }
 
index eaf0b65feec860c58e6622182672f6a7ec2e0760..d41f9d64c7534e580e0459e3691aa0c55e87c352 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from standaloneusers/xml/schema/CRM/Standaloneusers/User.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7f2d1d449d263061c7db7a6c5d57c27d)
+ * (GenCodeChecksum:8b4f87b26bd48490757533b57378e33d)
  */
 use CRM_Standaloneusers_ExtensionUtil as E;
 
@@ -92,7 +92,7 @@ class CRM_Standaloneusers_DAO_User extends CRM_Core_DAO {
   public $email;
 
   /**
-   * FK to values from OptionGroup role
+   * FK to Role
    *
    * @var string|null
    *   (SQL type: varchar(128))
@@ -301,7 +301,7 @@ class CRM_Standaloneusers_DAO_User extends CRM_Core_DAO {
           'name' => 'roles',
           'type' => CRM_Utils_Type::T_STRING,
           'title' => E::ts('Roles'),
-          'description' => E::ts('FK to values from OptionGroup role'),
+          'description' => E::ts('FK to Role'),
           'maxlength' => 128,
           'size' => CRM_Utils_Type::HUGE,
           'usage' => [
@@ -320,8 +320,10 @@ class CRM_Standaloneusers_DAO_User extends CRM_Core_DAO {
             'type' => 'Select',
           ],
           'pseudoconstant' => [
-            'optionGroupName' => 'role',
-            'optionEditPath' => 'civicrm/admin/options/role',
+            'table' => 'civicrm_role',
+            'keyColumn' => 'id',
+            'labelColumn' => 'label',
+            'nameColumn' => 'name',
           ],
           'add' => NULL,
         ],
similarity index 60%
rename from ext/standaloneusers/Civi/Api4/RolePermission.php
rename to ext/standaloneusers/Civi/Api4/Role.php
index df2231164000973d6cb0ff31820abdade7c9e3a4..678779fa3a630cf3421d9abfa9865bf09dad4a99 100644 (file)
@@ -2,12 +2,12 @@
 namespace Civi\Api4;
 
 /**
- * RolePermission entity.
+ * Role entity.
  *
  * Provided by the Standalone Users extension.
  *
  * @package Civi\Api4
  */
-class RolePermission extends Generic\DAOEntity {
+class Role extends Generic\DAOEntity {
 
 }
index c2f4e2cead09011b620d2d8932a674093c759f17..3014805bcd57d140dd5b604f9b65d404a2adbdea 100644 (file)
@@ -64,6 +64,7 @@ class Security {
   public function checkPermission(\CRM_Core_Permission_Standalone $permissionObject, string $permissionName, $userID) {
 
     // I think null means the current logged-in user
+    xdebug_break();
     $userID = $userID ?? $this->getLoggedInUfID();
 
     if (!$userID) {
@@ -71,19 +72,28 @@ class Security {
       return FALSE;
     }
 
-    // @todo handle anonymous permissions!
+    if (!isset(\Civi::$statics[__METHOD__][$userID])) {
+      if ($userID) {
+        $roleIDs = \Civi\Api4\User::get(FALSE)->addWhere('id', '=', $userID)
+          ->addSelect('roles')->execute()->first()['roles'];
+        // Grant the 'Everyone' role, too.
+        $roleIDs[] = 1;
+      }
+      else {
+        // Everyone
+        $roleIDs = [1];
+      }
 
-    $roleIDs = \Civi\Api4\User::get(FALSE)->addWhere('id', '=', $userID)
-      ->addSelect('roles')->execute()->first()['roles'];
+      $permissionsPerRole = \Civi\Api4\Role::get(FALSE)
+        ->addSelect('permissions')
+        ->addWhere('id', 'IN', $roleIDs)
+      // ->addWhere('is_active', '=', TRUE) @todo
+        ->execute()->column('permissions');
+      $permissions = array_unique(array_merge(...$permissionsPerRole));
+      \Civi::$statics[__METHOD__][$userID] = $permissions;
+    }
 
-    // artfulrobot: I think we should cache these per request, e.g. Civi::$statics?
-    // except in testing permissions shouldn't change during a request. @todo
-    $found = \Civi\Api4\RolePermission::get(FALSE)
-      ->selectRowCount()
-      ->addWhere('role_id', 'IN', $roleIDs)
-      ->addWhere('permission', '=', $permissionName)
-      ->execute()->countMatched();
-    return (bool) $found;
+    return in_array($permissionName, \Civi::$statics[__METHOD__][$userID]);
   }
 
   /**
@@ -143,7 +153,7 @@ class Security {
    *    - 'cms_pass' plaintext password
    *    - 'notify' boolean
    * @param string $mail
-   *   Email id for cms user.
+   *   Email address for cms user.
    *
    * @return int|bool
    *   uid if user was created, false otherwise
diff --git a/ext/standaloneusers/managed/OptionGroup_role.mgd.php b/ext/standaloneusers/managed/OptionGroup_role.mgd.php
deleted file mode 100644 (file)
index 6cde7cb..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-use CRM_Standaloneusers_ExtensionUtil as E;
-
-return [
-  [
-    'name' => 'OptionGroup_role',
-    'entity' => 'OptionGroup',
-    'cleanup' => 'unused',
-    'update' => 'unmodified',
-    'params' => [
-      'version' => 4,
-      'values' => [
-        'name' => 'role',
-        'title' => E::ts('Role'),
-        'description' => E::ts('A role is grants permissions to users in CiviCRM Standalone.'),
-        'data_type' => 'Integer',
-        'is_reserved' => TRUE,
-        'is_active' => TRUE,
-        'is_locked' => FALSE,
-        'option_value_fields' => [
-          'label',
-          'description',
-          'icon',
-          'color',
-          'name',
-        ],
-      ],
-      'match' => [
-        'name',
-      ],
-    ],
-  ],
-  [
-    'name' => 'OptionGroup_role_OptionValue_admin',
-    'entity' => 'OptionValue',
-    'cleanup' => 'unused',
-    'update' => 'unmodified',
-    'params' => [
-      'version' => 4,
-      'values' => [
-        'option_group_id.name' => 'role',
-        'label' => E::ts('Administrator'),
-        'value' => '1',
-        'name' => 'admin',
-        'grouping' => NULL,
-        'filter' => 0,
-        'is_default' => FALSE,
-        'description' => NULL,
-        'is_optgroup' => FALSE,
-        'is_reserved' => TRUE,
-        'is_active' => TRUE,
-        'component_id' => NULL,
-        'domain_id' => NULL,
-        'visibility_id' => NULL,
-        'icon' => NULL,
-        'color' => NULL,
-      ],
-      'match' => [
-        'name',
-        'option_group_id',
-      ],
-    ],
-  ],
-];
index c03740accf608db1cf115c97bcc241a54183a1c1..6bec096b99db0b8b31f2b3991f99610432fc8d2a 100644 (file)
@@ -18,7 +18,7 @@
 SET FOREIGN_KEY_CHECKS=0;
 
 DROP TABLE IF EXISTS `civicrm_user`;
-DROP TABLE IF EXISTS `civicrm_role_permission`;
+DROP TABLE IF EXISTS `civicrm_role`;
 
 SET FOREIGN_KEY_CHECKS=1;
 -- /*******************************************************
@@ -29,15 +29,17 @@ SET FOREIGN_KEY_CHECKS=1;
 
 -- /*******************************************************
 -- *
--- * civicrm_role_permission
+-- * civicrm_role
 -- *
--- * Assigns permissions to roles
+-- * A Role holds a set of permissions. Roles may be granted to Users.
 -- *
 -- *******************************************************/
-CREATE TABLE `civicrm_role_permission` (
-  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique RolePermission ID',
-  `role_id` int unsigned COMMENT 'FK to a role option value',
-  `permission` varchar(60) NOT NULL COMMENT 'A single permission granted to this role',
+CREATE TABLE `civicrm_role` (
+  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique Role ID',
+  `name` varchar(60) NOT NULL COMMENT 'Machine name for this role',
+  `label` varchar(128) NOT NULL COMMENT 'Human friendly name for this role',
+  `permissions` text NOT NULL COMMENT 'List of permissions granted by this role',
+  `is_active` tinyint DEFAULT 1 COMMENT 'Only active roles grant permissions',
   PRIMARY KEY (`id`)
 )
 ENGINE=InnoDB;
@@ -55,7 +57,7 @@ CREATE TABLE `civicrm_user` (
   `username` varchar(60) NOT NULL,
   `password` varchar(128) NOT NULL COMMENT 'Hashed password',
   `email` varchar(255) NOT NULL COMMENT 'Email (e.g. for password resets)',
-  `roles` varchar(128) COMMENT 'FK to values from OptionGroup role',
+  `roles` varchar(128) COMMENT 'FK to Role',
   `when_created` timestamp DEFAULT CURRENT_TIMESTAMP,
   `when_last_accessed` timestamp NULL,
   `when_updated` timestamp NULL,
index 6485a0f1ef39d4fec48b41bfb34f996eff582931..f754abde63ab098603b029ffb399afb24e12249b 100644 (file)
@@ -16,6 +16,6 @@
 SET FOREIGN_KEY_CHECKS=0;
 
 DROP TABLE IF EXISTS `civicrm_user`;
-DROP TABLE IF EXISTS `civicrm_role_permission`;
+DROP TABLE IF EXISTS `civicrm_role`;
 
 SET FOREIGN_KEY_CHECKS=1;
\ No newline at end of file
index 97db8a5f90e771ad543d978c5e49f8f50f4ca94e..9336b7ae2317c1a89812725652f1fe3af87703d0 100644 (file)
@@ -74,39 +74,26 @@ class SecurityTest extends \PHPUnit\Framework\TestCase implements EndToEndInterf
     [$contactID, $userID, $security] = $this->createFixtureContactAndUser();
 
     // Create a custom role
-    $roleID = \Civi\Api4\OptionValue::create(FALSE)
+    $roleID = \Civi\Api4\Role::create(FALSE)
       ->setValues([
-        'option_group_id.name' => 'role',
         'name' => 'demo_role',
         'label' => 'demo_role',
-      ])->execute()->first()['value'];
+        'permissions' => [
+            // Main control for access to the main CiviCRM backend and API. Give to trusted roles only.
+          'access CiviCRM',
+          'view all contacts',
+          'add contacts',
+          'edit all contacts',
+           // 'administer CiviCRM' // Perform all tasks in the Administer CiviCRM control panel and Import Contacts
+        ],
+      ])->execute()->first()['id'];
 
     // Give our user this role only.
     \Civi\Api4\User::update(FALSE)
-      ->addValue('roles', [$roleID])
+      ->addValue('roles:name', ['demo_role'])
       ->addWhere('id', '=', $userID)
       ->execute();
 
-    $existingPermissions = \Civi\Api4\RolePermission::get(FALSE)
-      ->selectRowCount()
-      ->addWhere('role_id', '=', $demoRoleID)
-      ->execute()->count();
-    $this->assertEquals(0, $existingPermissions);
-
-    // Assign some permissions to the role.
-    \Civi\Api4\RolePermission::save(FALSE)
-      ->setDefaults(['role_id' => $roleID])
-      ->setRecords([
-      // Master control for access to the main CiviCRM backend and API. Give to trusted roles only.
-      ['permission' => 'access CiviCRM'],
-      // Perform all tasks in the Administer CiviCRM control panel and Import Contacts
-      // ['permission' => 'administer CiviCRM'],
-      ['permission' => 'view all contacts'],
-      ['permission' => 'add contacts'],
-      ['permission' => 'edit all contacts'],
-      ])
-      ->execute();
-
     $this->switchToOurUFClasses();
     foreach (['access CiviCRM', 'view all contacts', 'add contacts', 'edit all contacts'] as $allowed) {
       $this->assertTrue(\CRM_Core_Permission::check([$allowed], $contactID), "Should have '$allowed' permission but don't");
similarity index 59%
rename from ext/standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.entityType.php
rename to ext/standaloneusers/xml/schema/CRM/Standaloneusers/Role.entityType.php
index 922e73b92d4c74fdaa7603c7961db5d17a4879d7..881922985e4ad37c638cffdb66093f41e4aa5437 100644 (file)
@@ -3,8 +3,8 @@
 // https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
 return [
   [
-    'name' => 'RolePermission',
-    'class' => 'CRM_Standaloneusers_DAO_RolePermission',
-    'table' => 'civicrm_role_permission',
+    'name' => 'Role',
+    'class' => 'CRM_Standaloneusers_DAO_Role',
+    'table' => 'civicrm_role',
   ],
 ];
diff --git a/ext/standaloneusers/xml/schema/CRM/Standaloneusers/Role.xml b/ext/standaloneusers/xml/schema/CRM/Standaloneusers/Role.xml
new file mode 100644 (file)
index 0000000..35a3b2c
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+
+<table>
+  <base>CRM/Standaloneusers</base>
+  <class>Role</class>
+  <name>civicrm_role</name>
+  <comment>A Role holds a set of permissions. Roles may be granted to Users.</comment>
+  <log>true</log>
+
+  <field>
+    <name>id</name>
+    <type>int unsigned</type>
+    <required>true</required>
+    <comment>Unique Role ID</comment>
+    <html>
+      <type>Number</type>
+    </html>
+  </field>
+  <primaryKey>
+    <name>id</name>
+    <autoincrement>true</autoincrement>
+  </primaryKey>
+
+  <field>
+    <name>name</name>
+    <comment>Machine name for this role</comment>
+    <type>varchar</type>
+    <length>60</length>
+    <required>true</required>
+  </field>
+
+  <field>
+    <name>label</name>
+    <comment>Human friendly name for this role</comment>
+    <type>varchar</type>
+    <length>128</length>
+    <required>true</required>
+  </field>
+
+  <field>
+    <name>permissions</name>
+    <comment>List of permissions granted by this role</comment>
+    <type>text</type>
+    <required>true</required>
+    <pseudoconstant>
+      <callback>CRM_Core_SelectValues::permissions</callback>
+    </pseudoconstant>
+    <html>
+      <type>Select</type>
+    </html>
+    <serialize>SEPARATOR_BOOKEND</serialize>
+  </field>
+
+  <field>
+    <name>is_active</name>
+    <title>Role is active</title>
+    <comment>Only active roles grant permissions</comment>
+    <type>boolean</type>
+    <default>1</default>
+    <html>
+      <type>CheckBox</type>
+    </html>
+  </field>
+
+</table>
diff --git a/ext/standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.xml b/ext/standaloneusers/xml/schema/CRM/Standaloneusers/RolePermission.xml
deleted file mode 100644 (file)
index 7d6abf6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
-
-<table>
-  <base>CRM/Standaloneusers</base>
-  <class>RolePermission</class>
-  <name>civicrm_role_permission</name>
-  <comment>Assigns permissions to roles</comment>
-  <log>true</log>
-
-  <field>
-    <name>id</name>
-    <type>int unsigned</type>
-    <required>true</required>
-    <comment>Unique RolePermission ID</comment>
-    <html>
-      <type>Number</type>
-    </html>
-  </field>
-  <primaryKey>
-    <name>id</name>
-    <autoincrement>true</autoincrement>
-  </primaryKey>
-
-  <field>
-    <name>role_id</name>
-    <type>int unsigned</type>
-    <comment>FK to a role option value</comment>
-    <pseudoconstant>
-      <optionGroupName>role</optionGroupName>
-    </pseudoconstant>
-  </field>
-
-  <field>
-    <name>permission</name>
-    <type>varchar</type>
-    <length>60</length>
-    <required>true</required>
-    <comment>A single permission granted to this role</comment>
-  </field>
-
-</table>
index db7b91cde0e5f5c50314ba4305d13f3f8fb4243c..8c199292aabb1fb96e31c9c13d60198fd37f457c 100644 (file)
     <type>varchar</type>
     <title>Roles</title>
     <length>128</length>
-    <comment>FK to values from OptionGroup role</comment>
+    <comment>FK to Role</comment>
     <pseudoconstant>
-      <optionGroupName>role</optionGroupName>
+      <table>civicrm_role</table>
+      <keyColumn>id</keyColumn>
+      <labelColumn>label</labelColumn>
+      <nameColumn>name</nameColumn>
     </pseudoconstant>
     <html>
       <type>Select</type>
index 692dc1b1b1ad059faf25a463890baaa2b6ce47a3..b8a3b0bfeda737e54cffedafe7deaa38d1e5f41c 100644 (file)
@@ -40,18 +40,24 @@ if (!defined('CIVI_SETUP')) {
 
     \Civi\Setup::log()->info(sprintf('[%s] Handle %s', basename(__FILE__), 'installDatabase'));
 
-    // admin should always be role 1 on install.
-    $roleID = 1;
-
-    // @todo I expect there's a better way than this; this doesn't even bring in all the permissions.
-    $records = [['permission' => 'authenticate with password']];
-    foreach (array_keys(\CRM_Core_Permission::getCorePermissions()) as $permission) {
-      $records[] = ['permission' => $permission];
-    }
-    \Civi\Api4\RolePermission::save(FALSE)
-      ->setDefaults(['role_id' => $roleID])
-      ->setRecords($records)
-      ->execute();
+    $roles = \Civi\Api4\Role::save(FALSE)
+      ->setDefaults([
+        'is_active' => TRUE,
+      ])
+      ->setRecords([
+        [
+          'name' => 'everyone',
+          'label' => 'Everyone, including anonymous users',
+    // @todo some standard ones, e.g. view civimail.
+          'permissions' => [],
+        ],
+        [
+          'name' => 'admin',
+          'label' => 'Administrator',
+          'permissions' => array_keys(\CRM_Core_SelectValues::permissions()),
+        ],
+      ])
+      ->execute()->indexBy('name');
 
     // Create contact+user for admin.
     $contactID = \Civi\Api4\Contact::create(FALSE)
@@ -66,7 +72,6 @@ if (!defined('CIVI_SETUP')) {
       'cms_name'   => $e->getModel()->extras['adminUser'],
       'cms_pass'   => $e->getModel()->extras['adminPass'],
       'notify'     => FALSE,
-      $adminEmail => $adminEmail,
       'contactID'  => $contactID,
     ];
     $userID = \CRM_Core_BAO_CMSUser::create($params, $adminEmail);
@@ -74,7 +79,7 @@ if (!defined('CIVI_SETUP')) {
     // Assign 'admin' role to user
     \Civi\Api4\User::update(FALSE)
       ->addWhere('id', '=', $userID)
-      ->addValue('roles', [$roleID])
+      ->addValue('roles:name', ['admin'])
       ->execute();
 
     $message = "Created new user \"{$e->getModel()->extras['adminUser']}\" (user ID #$userID, contact ID #$contactID) with 'admin' role and ";