SearchKit - Improve metadata for ContactType & add standalone path to edit form
authorColeman Watts <coleman@civicrm.org>
Tue, 13 Sep 2022 21:08:03 +0000 (17:08 -0400)
committerColeman Watts <coleman@civicrm.org>
Wed, 14 Sep 2022 12:35:41 +0000 (08:35 -0400)
Giving the listing page and the edit form seperate url paths allow each
to be replaced incrimentally by the civicrm_admin_ui extension.

CRM/Admin/Form/ContactType.php
CRM/Admin/Page/ContactType.php
CRM/Contact/BAO/ContactType.php
CRM/Contact/DAO/ContactType.php
CRM/Core/xml/Menu/Admin.xml
CRM/Utils/Check/Component/ContactTypes.php
Civi/Api4/ContactType.php
Civi/Api4/Generic/DAODeleteAction.php
ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
xml/schema/Contact/ContactType.xml

index 386bd4785c49c0799a828d148a90ee53d7e0a327..676a7e4e9758e87781be8fa78f049e9808d8e4d3 100644 (file)
  */
 class CRM_Admin_Form_ContactType extends CRM_Admin_Form {
 
+  public function preProcess(): void {
+    CRM_Utils_Request::retrieve('action', 'String', $this);
+    CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0);
+    $this->set('BAOName', 'CRM_Contact_BAO_ContactType');
+    parent::preProcess();
+  }
+
   /**
    * Build the form object.
    */
index be396a9709fe51c42485da6bcc09806255e5a3d1..593c583f3c49face3f77d9bfac49ef55a88ffa90 100644 (file)
@@ -50,7 +50,7 @@ class CRM_Admin_Page_ContactType extends CRM_Core_Page_Basic {
       self::$_links = [
         CRM_Core_Action::UPDATE => [
           'name' => ts('Edit'),
-          'url' => 'civicrm/admin/options/subtype',
+          'url' => 'civicrm/admin/options/subtype/edit',
           'qs' => 'action=update&id=%%id%%&reset=1',
           'title' => ts('Edit Contact Type'),
         ],
@@ -66,7 +66,7 @@ class CRM_Admin_Page_ContactType extends CRM_Core_Page_Basic {
         ],
         CRM_Core_Action::DELETE => [
           'name' => ts('Delete'),
-          'url' => 'civicrm/admin/options/subtype',
+          'url' => 'civicrm/admin/options/subtype/edit',
           'qs' => 'action=delete&id=%%id%%',
           'title' => ts('Delete Contact Type'),
         ],
@@ -81,7 +81,6 @@ class CRM_Admin_Page_ContactType extends CRM_Core_Page_Basic {
   public function run() {
     $action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 0);
     $this->assign('action', $action);
-    $id = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0);
     if (!$action) {
       $this->browse();
     }
index dfafc2c0c751b19453e54c82c68fe355a3c7bb48..dcf4150abde944428764b5968503f3d54c6cc106 100644 (file)
@@ -886,4 +886,24 @@ WHERE ($subtypeClause)";
     return $contactTypes;
   }
 
+  /**
+   * @param string $entityName
+   * @param string $action
+   * @param array $record
+   * @param $userID
+   * @return bool
+   * @see CRM_Core_DAO::checkAccess
+   */
+  public static function _checkAccess(string $entityName, string $action, array $record, $userID): bool {
+    // Only records with a parent may be deleted
+    if ($action === 'delete') {
+      if (!array_key_exists('parent_id', $record)) {
+        $record['parent_id'] = CRM_Core_DAO::getFieldValue(parent::class, $record['id'], 'parent_id');
+      }
+      return (bool) $record['parent_id'];
+    }
+    // Gatekeeper permissions suffice for everything else
+    return TRUE;
+  }
+
 }
index 0ae0d52748923458a554b9082d72aa44549050e8..6d795d0493f058fc61e7938f73b259e41ddd2a14 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/ContactType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:13c81c203681009e8f71fd8387ebdbc2)
+ * (GenCodeChecksum:9858d69cd4bfdc5a3ce45c77eecd1145)
  */
 
 /**
@@ -30,6 +30,17 @@ class CRM_Contact_DAO_ContactType extends CRM_Core_DAO {
    */
   public static $_log = FALSE;
 
+  /**
+   * Paths for accessing this entity in the UI.
+   *
+   * @var string[]
+   */
+  protected static $_paths = [
+    'add' => 'civicrm/admin/options/subtype/edit?action=add&reset=1',
+    'update' => 'civicrm/admin/options/subtype/edit?action=update&id=[id]&reset=1',
+    'delete' => 'civicrm/admin/options/subtype/edit?action=delete&id=[id]&reset=1',
+  ];
+
   /**
    * Contact Type ID
    *
index 596018228addb6c86791eee51003e92414f3ba84..030b2b03d9743bd3fcd0124e9976fa08ce666b19 100644 (file)
      <adminGroup>Customize Data and Screens</adminGroup>
      <weight>40</weight>
   </item>
+  <item>
+     <path>civicrm/admin/options/subtype/edit</path>
+     <title>Edit Contact Type</title>
+     <page_callback>CRM_Admin_Form_ContactType</page_callback>
+  </item>
   <item>
      <path>civicrm/admin/options/gender</path>
      <title>Gender Options</title>
index bfd2983d1f5b1f2f72de429f0a9d2ce477be7587..ebeee75f9d68bae6836a23f85f35ca294cef006f 100644 (file)
@@ -41,7 +41,7 @@ class CRM_Utils_Check_Component_ContactTypes extends CRM_Utils_Check_Component {
         'fa-picture-o'
       );
       foreach ($contactTypesWithImages as $contactType) {
-        $message->addAction($contactType['label'], FALSE, 'href', ['path' => 'civicrm/admin/options/subtype', 'query' => ['action' => 'update', 'id' => $contactType['id'], 'reset' => 1]], 'fa-pencil');
+        $message->addAction($contactType['label'], FALSE, 'href', ['path' => 'civicrm/admin/options/subtype/edit', 'query' => ['action' => 'update', 'id' => $contactType['id'], 'reset' => 1]], 'fa-pencil');
       }
       $messages[] = $message;
     }
index e949845613a168a4e8f6decb856397471e899e6b..cf478def15b1a5abb14a014af4a3db8612733b4a 100644 (file)
@@ -21,7 +21,7 @@ namespace Civi\Api4;
  *
  * @see https://docs.civicrm.org/user/en/latest/organising-your-data/contacts/#contact-subtypes
  * @see \Civi\Api4\Contact
- * @searchable none
+ * @searchable secondary
  * @since 5.19
  * @package Civi\Api4
  */
index 3dbab24757117ebff7697b6a39b3a198db497c8d..cd7a32fc1d5534740074c691b3671fa1a25c9e02 100644 (file)
@@ -36,8 +36,10 @@ class DAODeleteAction extends AbstractBatchAction {
     $items = $this->getBatchRecords();
 
     if ($this->getCheckPermissions()) {
+      $idField = CoreUtil::getIdFieldName($this->getEntityName());
       foreach ($items as $key => $item) {
-        if (!CoreUtil::checkAccessRecord($this, $item, \CRM_Core_Session::getLoggedInContactID() ?: 0)) {
+        // Don't pass the entire item because only the id is a trusted value
+        if (!CoreUtil::checkAccessRecord($this, [$idField => $item[$idField]], \CRM_Core_Session::getLoggedInContactID() ?: 0)) {
           throw new UnauthorizedException("ACL check failed");
         }
         $items[$key]['check_permissions'] = TRUE;
index 6d417c4baf7f454c0d97b2b8dddf364882c0a362..b06f67c8192e3a06da992e2b38ca330b69e1308c 100644 (file)
@@ -509,18 +509,21 @@ abstract class AbstractRunAction extends \Civi\Api4\Generic\AbstractAction {
       if ($prefix) {
         $path = str_replace('[', '[' . $prefix, $path);
       }
-      // Check access for edit/update links
+      // Check access for edit/update/delete links
       // (presumably if a record is shown in SearchKit the user already has view access, and the check is expensive)
       if ($path && isset($data) && !in_array($link['action'], ['view', 'preview'], TRUE)) {
         $id = $data[$prefix . $idKey] ?? NULL;
         $id = is_array($id) ? $id[$index] ?? NULL : $id;
         if ($id) {
+          $values = [$idField => $id];
+          // If not aggregated, add other values to help checkAccess be efficient
+          if (!is_array($data[$prefix . $idKey])) {
+            $values += \CRM_Utils_Array::filterByPrefix($data, $prefix);
+          }
           $access = civicrm_api4($link['entity'], 'checkAccess', [
             // Fudge links with funny action names to check 'update'
             'action' => $link['action'] === 'delete' ? 'delete' : 'update',
-            'values' => [
-              $idField => $id,
-            ],
+            'values' => $values,
           ], 0)['access'];
           if (!$access) {
             return NULL;
index b9fe0b75b5720c0cb257a4eceb584ae59d69051b..aec9c423fa900886ec57ca1250bbdc4c8a40f9a6 100644 (file)
@@ -6,6 +6,11 @@
   <name>civicrm_contact_type</name>
   <comment>Provide type information for contacts</comment>
   <add>3.1</add>
+  <paths>
+    <add>civicrm/admin/options/subtype/edit?action=add&amp;reset=1</add>
+    <update>civicrm/admin/options/subtype/edit?action=update&amp;id=[id]&amp;reset=1</update>
+    <delete>civicrm/admin/options/subtype/edit?action=delete&amp;id=[id]&amp;reset=1</delete>
+  </paths>
   <field>
     <name>id</name>
     <title>Contact Type ID</title>