dev/core#4542 Fix priority handling in ACLs when dealing with objects other than...
authorsebalis <sebalis@gmx.net>
Sat, 9 Sep 2023 00:56:50 +0000 (02:56 +0200)
committersebalis <sebalis@gmx.net>
Sat, 9 Sep 2023 01:08:16 +0000 (03:08 +0200)
Co-authored-by: Seamus Lee <seamuslee001@gmail.com>
CRM/ACL/BAO/ACL.php

index ab6495a15777f0f293fc709606ac304ac4d6e7bc..be0673a50ae8fb3112a3ff1f59fe3aac7c9b690a 100644 (file)
@@ -222,31 +222,13 @@ SELECT count( a.id )
    * @return null|string
    */
   public static function whereClause($type, &$tables, &$whereTables, $contactID = NULL) {
-    $acls = CRM_ACL_BAO_Cache::build($contactID);
 
     $whereClause = NULL;
     $allInclude = $allExclude = FALSE;
     $clauses = [];
 
-    if (!empty($acls)) {
-      $aclKeys = array_keys($acls);
-      $aclKeys = implode(',', $aclKeys);
-      $orderBy = 'a.object_id';
-      if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) {
-        $orderBy .= ',a.priority';
-      }
-      $query = "
-SELECT   a.operation, a.object_id,a.deny
-  FROM   civicrm_acl_cache c, civicrm_acl a
- WHERE   c.acl_id       =  a.id
-   AND   a.is_active    =  1
-   AND   a.object_table = 'civicrm_group'
-   AND   a.id        IN ( $aclKeys )
-ORDER BY {$orderBy}
-";
-
-      $dao = CRM_Core_DAO::executeQuery($query);
-
+    $dao = self::getOrderedActiveACLs($contactID, 'civicrm_group');
+    if ($dao !== NULL) {
       // do an or of all the where clauses u see
       $ids = $excludeIds = [];
       while ($dao->fetch()) {
@@ -451,54 +433,73 @@ ORDER BY {$orderBy}
    */
   protected static function loadPermittedIDs(int $contactID, string $tableName, int $type, $allGroups): array {
     $ids = [];
-    $acls = CRM_ACL_BAO_Cache::build($contactID);
-    $aclKeys = array_keys($acls);
-    $aclKeys = implode(',', $aclKeys);
-    $orderBy = 'a.object_id';
-    if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) {
-      $orderBy .= ',a.priority';
-    }
-    $query = "
-SELECT   a.operation,a.object_id,a.deny
-  FROM   civicrm_acl_cache c, civicrm_acl a
- WHERE   c.acl_id       =  a.id
-   AND   a.is_active    =  1
-   AND   a.object_table = %1
-   AND   a.id        IN ( $aclKeys )
-ORDER BY {$orderBy}
-";
-    $params = [1 => [$tableName, 'String']];
-    $dao = CRM_Core_DAO::executeQuery($query, $params);
-    while ($dao->fetch()) {
-      if ($dao->object_id) {
-        if (self::matchType($type, $dao->operation)) {
-          if (!$dao->deny) {
-            $ids[] = $dao->object_id;
-          }
-          else {
-            $ids = array_diff($ids, [$dao->object_id]);
+    $dao = self::getOrderedActiveACLs($contactID, $tableName);
+    if ($dao !== NULL) {
+      while ($dao->fetch()) {
+        if ($dao->object_id) {
+          if (self::matchType($type, $dao->operation)) {
+            if (!$dao->deny) {
+              $ids[] = $dao->object_id;
+            }
+            else {
+              $ids = array_diff($ids, [$dao->object_id]);
+            }
           }
         }
-      }
-      else {
-        // this user has got the permission for all objects of this type
-        // check if the type matches
-        if (self::matchType($type, $dao->operation)) {
-          if (!$dao->deny) {
-            foreach ($allGroups as $id => $dontCare) {
-              $ids[] = $id;
+        else {
+          // this user has got the permission for all objects of this type
+          // check if the type matches
+          if (self::matchType($type, $dao->operation)) {
+            if (!$dao->deny) {
+              foreach ($allGroups as $id => $dontCare) {
+                $ids[] = $id;
+              }
+            }
+            else {
+              $ids = array_diff($ids, array_keys($allGroups));
             }
-          }
-          else {
-            $ids = array_diff($ids, array_keys($allGroups));
           }
         }
-        break;
       }
     }
     return $ids;
   }
 
+  /**
+   * Execute a query to find active ACLs for a contact, ordered by priority (if supported) and object ID.
+   * The query returns the 'operation', 'object_id' and 'deny' properties.
+   * Returns NULL if CRM_ACL_BAO_Cache::build (effectively, CRM_ACL_BAO_ACL::getAllByContact)
+   * returns no ACLs (active or not) for the contact.
+   *
+   * @param string $contactID
+   * @param string $tableName
+   * @return NULL|CRM_Core_DAO|object
+   */
+  private static function getOrderedActiveACLs(string $contactID, string $tableName) {
+    $dao = NULL;
+    $acls = CRM_ACL_BAO_Cache::build($contactID);
+    if (!empty($acls)) {
+      $aclKeys = array_keys($acls);
+      $aclKeys = implode(',', $aclKeys);
+      $orderBy = 'a.object_id';
+      if (array_key_exists('priority', CRM_ACL_BAO_ACL::getSupportedFields())) {
+        $orderBy = "a.priority, $orderBy";
+      }
+      $query = "
+SELECT   a.operation, a.object_id, a.deny
+  FROM   civicrm_acl_cache c, civicrm_acl a
+ WHERE   c.acl_id       =  a.id
+   AND   a.is_active    =  1
+   AND   a.object_table = %1
+   AND   a.id        IN ({$aclKeys})
+ORDER BY {$orderBy}
+";
+      $params = [1 => [$tableName, 'String']];
+      $dao = CRM_Core_DAO::executeQuery($query, $params);
+    }
+    return $dao;
+  }
+
   private static function getGroupClause(array $groupIDs, string $operation): string {
     $ids = implode(',', $groupIDs);
     $query = "