0562921998181931e380e2ad0361a9ab98a1885d
[civicrm-core.git] / CRM / ACL / BAO / ACL.php
1 <?php
2 // $Id$
3
4 /*
5 +--------------------------------------------------------------------+
6 | CiviCRM version 4.3 |
7 +--------------------------------------------------------------------+
8 | Copyright CiviCRM LLC (c) 2004-2013 |
9 +--------------------------------------------------------------------+
10 | This file is a part of CiviCRM. |
11 | |
12 | CiviCRM is free software; you can copy, modify, and distribute it |
13 | under the terms of the GNU Affero General Public License |
14 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
15 | |
16 | CiviCRM is distributed in the hope that it will be useful, but |
17 | WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
19 | See the GNU Affero General Public License for more details. |
20 | |
21 | You should have received a copy of the GNU Affero General Public |
22 | License and the CiviCRM Licensing Exception along |
23 | with this program; if not, contact CiviCRM LLC |
24 | at info[AT]civicrm[DOT]org. If you have questions about the |
25 | GNU Affero General Public License or the licensing of CiviCRM, |
26 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
27 +--------------------------------------------------------------------+
28 */
29
30 /**
31 *
32 * @package CRM
33 * @copyright CiviCRM LLC (c) 2004-2013
34 * $Id$
35 *
36 */
37
38 /**
39 * Access Control List
40 */
41 class CRM_ACL_BAO_ACL extends CRM_ACL_DAO_ACL {
42 static $_entityTable = NULL;
43 static $_objectTable = NULL;
44 static $_operation = NULL;
45
46 static $_fieldKeys = NULL;
47
48 static function entityTable() {
49 if (!self::$_entityTable) {
50 self::$_entityTable = array(
51 'civicrm_contact' => ts('Contact'),
52 'civicrm_acl_role' => ts('ACL Role'),
53 );
54 }
55 return self::$_entityTable;
56 }
57
58 static function objectTable() {
59 if (!self::$_objectTable) {
60 self::$_objectTable = array(
61 'civicrm_contact' => ts('Contact'),
62 'civicrm_group' => ts('Group'),
63 'civicrm_saved_search' => ts('Contact Group'),
64 'civicrm_admin' => ts('Administer'),
65 'civicrm_admin' => ts('Import'),
66 );
67 }
68 return self::$_objectTable;
69 }
70
71 static function operation() {
72 if (!self::$_operation) {
73 self::$_operation = array(
74 'View' => ts('View'),
75 'Edit' => ts('Edit'),
76 'Create' => ts('Create'),
77 'Delete' => ts('Delete'),
78 'Search' => ts('Search'),
79 'All' => ts('All'),
80 );
81 }
82 return self::$_operation;
83 }
84
85 /**
86 * Construct a WHERE clause to handle permissions to $object_*
87 *
88 * @param array ref $tables - Any tables that may be needed in the FROM
89 * @param string $operation - The operation being attempted
90 * @param string $object_table - The table of the object in question
91 * @param int $object_id - The ID of the object in question
92 * @param int $acl_id - If it's a grant/revoke operation, the ACL ID
93 * @param boolean $acl_role - For grant operations, this flag determines if we're granting a single acl (false) or an entire group.
94 *
95 * @return string - The WHERE clause, or 0 on failure
96 * @access public
97 * @static
98 */
99 public static function permissionClause(&$tables, $operation,
100 $object_table = NULL, $object_id = NULL,
101 $acl_id = NULL, $acl_role = FALSE
102 ) {
103 $dao = new CRM_ACL_DAO_ACL;
104
105 $t = array(
106 'ACL' => self::getTableName(),
107 'ACLRole' => 'civicrm_acl_role',
108 'ACLEntityRole' => CRM_ACL_DAO_EntityRole::getTableName(),
109 'Contact' => CRM_Contact_DAO_Contact::getTableName(),
110 'Group' => CRM_Contact_DAO_Group::getTableName(),
111 'GroupContact' => CRM_Contact_DAO_GroupContact::getTableName(),
112 );
113
114 $session = CRM_Core_Session::singleton();
115 $contact_id = $session->get('userID');
116
117 $where = " {$t['ACL']}.operation = '" . CRM_Utils_Type::escape($operation, 'String') . "'";
118
119 /* Include clause if we're looking for a specific table/id permission */
120
121
122 if (!empty($object_table)) {
123 $where .= " AND ( {$t['ACL']}.object_table IS null
124 OR ({$t['ACL']}.object_table = '" . CRM_Utils_Type::escape($object_table, 'String') . "'";
125 if (!empty($object_id)) {
126 $where .= " AND ({$t['ACL']}.object_id IS null
127 OR {$t['ACL']}.object_id = " . CRM_Utils_Type::escape($object_id, 'Integer') . ')';
128 }
129 $where .= '))';
130 }
131
132 /* Include clause if we're granting an ACL or ACL Role */
133
134
135 if (!empty($acl_id)) {
136 $where .= " AND ({$t['ACL']}.acl_id IS null
137 OR {$t['ACL']}.acl_id = " . CRM_Utils_Type::escape($acl_id, 'Integer') . ')';
138 if ($acl_role) {
139 $where .= " AND {$t['ACL']}.acl_table = '{$t['ACLRole']}'";
140 }
141 else {
142 $where .= " AND {$t['ACL']}.acl_table = '{$t['ACL']}'";
143 }
144 }
145
146 $query = array();
147
148 /* Query for permissions granted to all contacts in the domain */
149
150
151 $query[] = "SELECT {$t['ACL']}.*, 0 as override
152 FROM {$t['ACL']}
153
154 WHERE {$t['ACL']}.entity_table = '{$t['Domain']}'
155 AND ($where)";
156
157 /* Query for permissions granted to all contacts through an ACL group */
158
159
160 $query[] = "SELECT {$t['ACL']}.*, 0 as override
161 FROM {$t['ACL']}
162
163 INNER JOIN {$t['ACLEntityRole']}
164 ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}'
165 AND {$t['ACL']}.entity_id =
166 {$t['ACLEntityRole']}.acl_role_id)
167
168 INNER JOIN {$t['ACLRole']}
169 ON {$t['ACL']}.entity_id =
170 {$t['ACLRole']}.id
171
172 WHERE {$t['ACLEntityRole']}.entity_table =
173 '{$t['Domain']}'
174 AND {$t['ACLRole']}.is_active = 1
175 AND ($where)";
176
177 /* Query for permissions granted directly to the contact */
178
179
180 $query[] = "SELECT {$t['ACL']}.*, 1 as override
181 FROM {$t['ACL']}
182
183 INNER JOIN {$t['Contact']}
184 ON ({$t['ACL']}.entity_table = '{$t['Contact']}'
185 AND {$t['ACL']}.entity_id = {$t['Contact']}.id)
186
187 WHERE {$t['Contact']}.id = $contact_id
188 AND ($where)";
189
190 /* Query for permissions granted to the contact through an ACL group */
191
192
193 $query[] = "SELECT {$t['ACL']}.*, 1 as override
194 FROM {$t['ACL']}
195
196 INNER JOIN {$t['ACLEntityRole']}
197 ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}'
198 AND {$t['ACL']}.entity_id =
199 {$t['ACLEntityRole']}.acl_role_id)
200
201 INNER JOIN {$t['ACLRole']}
202 ON {$t['ACL']}.entity_id = {$t['ACLRole']}.id
203
204 WHERE {$t['ACLEntityRole']}.entity_table =
205 '{$t['Contact']}'
206 AND {$t['ACLRole']}.is_active = 1
207 AND {$t['ACLEntityRole']}.entity_id = $contact_id
208 AND ($where)";
209
210 /* Query for permissions granted to the contact through a group */
211
212
213 $query[] = "SELECT {$t['ACL']}.*, 0 as override
214 FROM {$t['ACL']}
215
216 INNER JOIN {$t['GroupContact']}
217 ON ({$t['ACL']}.entity_table = '{$t['Group']}'
218 AND {$t['ACL']}.entity_id =
219 {$t['GroupContact']}.group_id)
220
221 WHERE ($where)
222 AND {$t['GroupContact']}.contact_id = $contact_id
223 AND {$t['GroupContact']}.status = 'Added')";
224
225
226 /* Query for permissions granted through an ACL group to a Contact
227 * group */
228
229
230 $query[] = "SELECT {$t['ACL']}.*, 0 as override
231 FROM {$t['ACL']}
232
233 INNER JOIN {$t['ACLEntityRole']}
234 ON ({$t['ACL']}.entity_table = '{$t['ACLRole']}'
235 AND {$t['ACL']}.entity_id =
236 {$t['ACLEntityRole']}.acl_role_id)
237
238 INNER JOIN {$t['ACLRole']}
239 ON {$t['ACL']}.entity_id = {$t['ACLRole']}.id
240
241 INNER JOIN {$t['GroupContact']}
242 ON ({$t['ACLEntityRole']}.entity_table =
243 '{$t['Group']}'
244 AND {$t['ACLEntityRole']}.entity_id =
245 {$t['GroupContact']}.group_id)
246
247 WHERE ($where)
248 AND {$t['ACLRole']}.is_active = 1
249 AND {$t['GroupContact']}.contact_id = $contact_id
250 AND {$t['GroupContact']}.status = 'Added'";
251
252 $union = '(' . implode(') UNION DISTINCT (', $query) . ')';
253
254 $dao->query($union);
255
256 $allow = array(0);
257 $deny = array(0);
258 $override = array();
259
260 while ($dao->fetch()) {
261 /* Instant bypass for the following cases:
262 * 1) the rule governs all tables
263 * 2) the rule governs all objects in the table in question
264 * 3) the rule governs the specific object we want
265 */
266
267
268 if (empty($dao->object_table) ||
269 ($dao->object_table == $object_table
270 && (empty($dao->object_id)
271 || $dao->object_id == $object_id
272 )
273 )
274 ) {
275 $clause = 1;
276 }
277 else {
278 /* Otherwise try to generate a clause for this rule */
279
280
281 $clause = self::getClause(
282 $dao->object_table, $dao->object_id, $tables
283 );
284
285 /* If the clause returned is null, then the rule is a blanket
286 * (id is null) on a table other than the one we're interested
287 * in. So skip it. */
288
289
290 if (empty($clause)) {
291 continue;
292 }
293 }
294
295 /* Now we figure out if this is an allow or deny rule, and possibly
296 * a contact-level override */
297
298
299 if ($dao->deny) {
300 $deny[] = $clause;
301 }
302 else {
303 $allow[] = $clause;
304
305 if ($dao->override) {
306 $override[] = $clause;
307 }
308 }
309 }
310
311 $allows = '(' . implode(' OR ', $allow) . ')';
312 $denies = '(' . implode(' OR ', $deny) . ')';
313 if (!empty($override)) {
314 $denies = '(NOT (' . implode(' OR ', $override) . ") AND $denies)";
315 }
316
317 return "($allows AND NOT $denies)";
318 }
319
320 /**
321 * Given a table and id pair, return the filter clause
322 *
323 * @param string $table - The table owning the object
324 * @param int $id - The ID of the object
325 * @param array ref $tables - Tables that will be needed in the FROM
326 *
327 * @return string|null - WHERE-style clause to filter results,
328 or null if $table or $id is null
329 * @access public
330 * @static
331 */
332 public static function getClause($table, $id, &$tables) {
333 $table = CRM_Utils_Type::escape($table, 'String');
334 $id = CRM_Utils_Type::escape($id, 'Integer');
335 $whereTables = array();
336
337 $ssTable = CRM_Contact_BAO_SavedSearch::getTableName();
338
339 if (empty($table)) {
340 return NULL;
341 }
342 elseif ($table == $ssTable) {
343 return CRM_Contact_BAO_SavedSearch::whereClause($id, $tables, $whereTables);
344 }
345 elseif (!empty($id)) {
346 $tables[$table] = TRUE;
347 return "$table.id = $id";
348 }
349 return NULL;
350 }
351
352 /**
353 * Construct an associative array of an ACL rule's properties
354 *
355 * @param string sprintf format for array
356 * @param bool empty only return elemnts that have a value set.
357 *
358 * @return array - Assoc. array of the ACL rule's properties
359 * @access public
360 */
361 function toArray($format = '%s', $hideEmpty = false) {
362 $result = array();
363
364 if (!self::$_fieldKeys) {
365 $fields = CRM_ACL_DAO_ACL::fields();
366 self::$_fieldKeys = array_keys($fields);
367 }
368
369 foreach (self::$_fieldKeys as $field) {
370 $result[$field] = $this->$field;
371 }
372 return $result;
373 }
374
375 /**
376 * Retrieve ACLs for a contact or group. Note that including a contact id
377 * without a group id will return those ACL rules which are granted
378 * directly to the contact, but not those granted to the contact through
379 * any/all of his group memberships.
380 *
381 * @param int $contact_id - ID of a contact to search for
382 * @param int $group_id - ID of a group to search for
383 * @param boolean $aclRoles - Should we include ACL Roles
384 *
385 * @return array - Array of assoc. arrays of ACL rules
386 * @access public
387 * @static
388 */
389 public static function &getACLs($contact_id = NULL, $group_id = NULL, $aclRoles = FALSE) {
390 $results = array();
391
392 if (empty($contact_id)) {
393 return $results;
394 }
395
396 $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer');
397 if ($group_id) {
398 $group_id = CRM_Utils_Type::escape($group_id, 'Integer');
399 }
400
401 $rule = new CRM_ACL_BAO_ACL();
402
403
404 $acl = self::getTableName();
405 $contact = CRM_Contact_BAO_Contact::getTableName();
406 $c2g = CRM_Contact_BAO_GroupContact::getTableName();
407 $group = CRM_Contact_BAO_Group::getTableName();
408
409 $query = " SELECT $acl.*
410 FROM $acl ";
411
412 if (!empty($group_id)) {
413 $query .= " INNER JOIN $c2g
414 ON $acl.entity_id = $c2g.group_id
415 WHERE $acl.entity_table = '$group'
416 AND $acl.is_active = 1
417 AND $c2g.group_id = $group_id";
418
419 if (!empty($contact_id)) {
420 $query .= " AND $c2g.contact_id = $contact_id
421 AND $c2g.status = 'Added'";
422 }
423 }
424 else {
425 if (!empty($contact_id)) {
426 $query .= " WHERE $acl.entity_table = '$contact'
427 AND $acl.entity_id = $contact_id";
428 }
429 }
430
431 $rule->query($query);
432
433 while ($rule->fetch()) {
434 $results[$rule->id] = $rule->toArray();
435 }
436
437 if ($aclRoles) {
438 $results += self::getACLRoles($contact_id, $group_id);
439 }
440
441 return $results;
442 }
443
444 /**
445 * Get all of the ACLs through ACL groups
446 *
447 * @param int $contact_id - ID of a contact to search for
448 * @param int $group_id - ID of a group to search for
449 *
450 * @return array - Array of assoc. arrays of ACL rules
451 * @access public
452 * @static
453 */
454 public static function &getACLRoles($contact_id = NULL, $group_id = NULL) {
455 $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer');
456 if ($group_id) {
457 $group_id = CRM_Utils_Type::escape($group_id, 'Integer');
458 }
459
460 $rule = new CRM_ACL_BAO_ACL();
461
462 $acl = self::getTableName();
463 $aclRole = 'civicrm_acl_role';
464 $aclRoleJoin = CRM_ACL_DAO_EntityRole::getTableName();
465 $contact = CRM_Contact_BAO_Contact::getTableName();
466 $c2g = CRM_Contact_BAO_GroupContact::getTableName();
467 $group = CRM_Contact_BAO_Group::getTableName();
468
469 $query = " SELECT $acl.*
470 FROM $acl
471 INNER JOIN civicrm_option_group og
472 ON og.name = 'acl_role'
473 INNER JOIN civicrm_option_value ov
474 ON $acl.entity_table = '$aclRole'
475 AND ov.option_group_id = og.id
476 AND $acl.entity_id = ov.value";
477
478 if (!empty($group_id)) {
479 $query .= " INNER JOIN $c2g
480 ON $acl.entity_id = $c2g.group_id
481 WHERE $acl.entity_table = '$group'
482 AND $acl.is_active = 1
483 AND $c2g.group_id = $group_id";
484
485 if (!empty($contact_id)) {
486 $query .= " AND $c2g.contact_id = $contact_id
487 AND $c2g.status = 'Added'";
488 }
489 }
490 else {
491 if (!empty($contact_id)) {
492 $query .= " WHERE $acl.entity_table = '$contact'
493 AND $acl.is_active = 1
494 AND $acl.entity_id = $contact_id";
495 }
496 }
497
498 $results = array();
499
500 $rule->query($query);
501
502 while ($rule->fetch()) {
503 $results[$rule->id] = $rule->toArray();
504 }
505
506 return $results;
507 }
508
509 /**
510 * Get all ACLs granted to a contact through all group memberships
511 *
512 * @param int $contact_id - The contact's ID
513 * @param boolean $aclRoles - Include ACL Roles?
514 *
515 * @return array - Assoc array of ACL rules
516 * @access public
517 * @static
518 */
519 public static function &getGroupACLs($contact_id, $aclRoles = FALSE) {
520 $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer');
521
522 $rule = new CRM_ACL_BAO_ACL();
523
524
525 $acl = self::getTableName();
526 $c2g = CRM_Contact_BAO_GroupContact::getTableName();
527 $group = CRM_Contact_BAO_Group::getTableName();
528 $results = array();
529
530 if ($contact_id) {
531 $query = "
532 SELECT $acl.*
533 FROM $acl
534 INNER JOIN $c2g
535 ON $acl.entity_id = $c2g.group_id
536 WHERE $acl.entity_table = '$group'
537 AND $c2g.contact_id = $contact_id
538 AND $c2g.status = 'Added'";
539
540 $rule->query($query);
541
542 while ($rule->fetch()) {
543 $results[$rule->id] = &$rule->toArray();
544 }
545 }
546
547 if ($aclRoles) {
548 $results += self::getGroupACLRoles($contact_id);
549 }
550
551 return $results;
552 }
553
554 /**
555 * Get all of the ACLs for a contact through ACL groups owned by Contact
556 * groups.
557 *
558 * @param int $contact_id - ID of a contact to search for
559 *
560 * @return array - Array of assoc. arrays of ACL rules
561 * @access public
562 * @static
563 */
564 public static function &getGroupACLRoles($contact_id) {
565 $contact_id = CRM_Utils_Type::escape($contact_id, 'Integer');
566
567 $rule = new CRM_ACL_BAO_ACL();
568
569 $acl = self::getTableName();
570 $aclRole = 'civicrm_acl_role';
571
572
573 $aclER = CRM_ACL_DAO_EntityRole::getTableName();
574 $c2g = CRM_Contact_BAO_GroupContact::getTableName();
575 $group = CRM_Contact_BAO_Group::getTableName();
576
577 $query = " SELECT $acl.*
578 FROM $acl
579 INNER JOIN civicrm_option_group og
580 ON og.name = 'acl_role'
581 INNER JOIN civicrm_option_value ov
582 ON $acl.entity_table = '$aclRole'
583 AND ov.option_group_id = og.id
584 AND $acl.entity_id = ov.value
585 AND ov.is_active = 1
586 INNER JOIN $aclER
587 ON $aclER.acl_role_id = $acl.entity_id
588 AND $aclER.is_active = 1
589 INNER JOIN $c2g
590 ON $aclER.entity_id = $c2g.group_id
591 AND $aclER.entity_table = 'civicrm_group'
592 WHERE $acl.entity_table = '$aclRole'
593 AND $acl.is_active = 1
594 AND $c2g.contact_id = $contact_id
595 AND $c2g.status = 'Added'";
596
597 $results = array();
598
599 $rule->query($query);
600
601 while ($rule->fetch()) {
602 $results[$rule->id] = &$rule->toArray();
603 }
604
605 // also get all acls for "Any Role" case
606 // and authenticated User Role if present
607 $roles = "0";
608 $session = CRM_Core_Session::singleton();
609 if ($session->get('ufID') > 0) {
610 $roles .= ",2";
611 }
612
613 $query = "
614 SELECT $acl.*
615 FROM $acl
616 WHERE $acl.entity_id IN ( $roles )
617 AND $acl.entity_table = 'civicrm_acl_role'
618 ";
619
620 $rule->query($query);
621 while ($rule->fetch()) {
622 $results[$rule->id] = $rule->toArray();
623 }
624
625 return $results;
626 }
627
628 /**
629 * Get all ACLs owned by a given contact, including domain and group-level.
630 *
631 * @param int $contact_id - The contact ID
632 *
633 * @return array - Assoc array of ACL rules
634 * @access public
635 * @static
636 */
637 public static function &getAllByContact($contact_id) {
638 $result = array();
639
640 /* First, the contact-specific ACLs, including ACL Roles */
641 $result += self::getACLs($contact_id, NULL, TRUE);
642
643 /* Then, all ACLs granted through group membership */
644 $result += self::getGroupACLs($contact_id, TRUE);
645
646 return $result;
647 }
648
649 static function create(&$params) {
650 $dao = new CRM_ACL_DAO_ACL();
651 $dao->copyValues($params);
652 $dao->save();
653 }
654
655 static function retrieve(&$params, &$defaults) {
656 CRM_Core_DAO::commonRetrieve('CRM_ACL_DAO_ACL', $params, $defaults);
657 }
658
659 /**
660 * update the is_active flag in the db
661 *
662 * @param int $id id of the database record
663 * @param boolean $is_active value we want to set the is_active field
664 *
665 * @return Object DAO object on sucess, null otherwise
666 * @static
667 */
668 static function setIsActive($id, $is_active) {
669 // note this also resets any ACL cache
670 CRM_Core_BAO_Cache::deleteGroup('contact fields');
671
672 return CRM_Core_DAO::setFieldValue('CRM_ACL_DAO_ACL', $id, 'is_active', $is_active);
673 }
674
675 static function check($str, $contactID) {
676
677 $acls = CRM_ACL_BAO_Cache::build($contactID);
678
679 $aclKeys = array_keys($acls);
680 $aclKeys = implode(',', $aclKeys);
681
682 if (empty($aclKeys)) {
683 return FALSE;
684 }
685
686
687 $query = "
688 SELECT count( a.id )
689 FROM civicrm_acl_cache c, civicrm_acl a
690 WHERE c.acl_id = a.id
691 AND a.is_active = 1
692 AND a.object_table = %1
693 AND a.id IN ( $aclKeys )
694 ";
695 $params = array(1 => array($str, 'String'));
696
697 $count = CRM_Core_DAO::singleValueQuery($query, $params);
698 return ($count) ? TRUE : FALSE;
699 }
700
701 public static function whereClause($type, &$tables, &$whereTables, $contactID = NULL) {
702 $acls = CRM_ACL_BAO_Cache::build($contactID);
703 //CRM_Core_Error::debug( "a: $contactID", $acls );
704
705 $whereClause = NULL;
706 $clauses = array();
707
708 if (!empty($acls)) {
709 $aclKeys = array_keys($acls);
710 $aclKeys = implode(',', $aclKeys);
711
712 $query = "
713 SELECT a.operation, a.object_id
714 FROM civicrm_acl_cache c, civicrm_acl a
715 WHERE c.acl_id = a.id
716 AND a.is_active = 1
717 AND a.object_table = 'civicrm_saved_search'
718 AND a.id IN ( $aclKeys )
719 ORDER BY a.object_id
720 ";
721
722 $dao = CRM_Core_DAO::executeQuery($query);
723
724 // do an or of all the where clauses u see
725 $ids = array();
726 while ($dao->fetch()) {
727 // make sure operation matches the type TODO
728 if (self::matchType($type, $dao->operation)) {
729 if (!$dao->object_id) {
730 $ids = array();
731 $whereClause = ' ( 1 ) ';
732 break;
733 }
734 $ids[] = $dao->object_id;
735 }
736 }
737
738 if (!empty($ids)) {
739 $ids = implode(',', $ids);
740 $query = "
741 SELECT g.*
742 FROM civicrm_group g
743 WHERE g.id IN ( $ids )
744 AND g.is_active = 1
745 ";
746 $dao = CRM_Core_DAO::executeQuery($query);
747 $staticGroupIDs = array();
748 $cachedGroupIDs = array();
749 while ($dao->fetch()) {
750 // currently operation is restrcited to VIEW/EDIT
751 if ($dao->where_clause) {
752 if ($dao->select_tables) {
753 $tmpTables = array();
754 foreach (unserialize($dao->select_tables) as $tmpName => $tmpInfo) {
755 if ($tmpName == '`civicrm_group_contact-' . $dao->id . '`') {
756 $tmpName = '`civicrm_group_contact-ACL`';
757 $tmpInfo = str_replace('civicrm_group_contact-' . $dao->id, 'civicrm_group_contact-ACL', $tmpInfo);
758 }
759 elseif ($tmpName == '`civicrm_group_contact_cache_' . $dao->id . '`') {
760 $tmpName = '`civicrm_group_contact_cache-ACL`';
761 $tmpInfo = str_replace('civicrm_group_contact_cache_' . $dao->id, 'civicrm_group_contact_cache-ACL', $tmpInfo);
762 }
763 $tmpTables[$tmpName] = $tmpInfo;
764 }
765 $tables = array_merge($tables,
766 $tmpTables
767 );
768 }
769 if ($dao->where_tables) {
770 $tmpTables = array();
771 foreach (unserialize($dao->where_tables) as $tmpName => $tmpInfo) {
772 if ($tmpName == '`civicrm_group_contact-' . $dao->id . '`') {
773 $tmpName = '`civicrm_group_contact-ACL`';
774 $tmpInfo = str_replace('civicrm_group_contact-' . $dao->id, 'civicrm_group_contact-ACL', $tmpInfo);
775 $staticGroupIDs[] = $dao->id;
776 }
777 elseif ($tmpName == '`civicrm_group_contact_cache_' . $dao->id . '`') {
778 $tmpName = '`civicrm_group_contact_cache-ACL`';
779 $tmpInfo = str_replace('civicrm_group_contact_cache_' . $dao->id, 'civicrm_group_contact_cache-ACL', $tmpInfo);
780 $cachedGroupIDs[] = $dao->id;
781 }
782 $tmpTables[$tmpName] = $tmpInfo;
783 }
784 $whereTables = array_merge($whereTables, $tmpTables);
785 }
786 }
787
788 if (($dao->saved_search_id || $dao->children || $dao->parents) &&
789 $dao->cache_date == NULL) {
790 CRM_Contact_BAO_GroupContactCache::load($dao);
791 }
792 }
793
794 if ($staticGroupIDs) {
795 $clauses[] = '( `civicrm_group_contact-ACL`.group_id IN (' . join(', ', $staticGroupIDs) . ') AND `civicrm_group_contact-ACL`.status IN ("Added") )';
796 }
797
798 if ($cachedGroupIDs) {
799 $clauses[] = '`civicrm_group_contact_cache-ACL`.group_id IN (' . join(', ', $cachedGroupIDs) . ')';
800 }
801 }
802 }
803
804 if (!empty($clauses)) {
805 $whereClause = ' ( ' . implode(' OR ', $clauses) . ' ) ';
806 }
807
808 // call the hook to get additional whereClauses
809 CRM_Utils_Hook::aclWhereClause($type, $tables, $whereTables, $contactID, $whereClause);
810
811 if (empty($whereClause)) {
812 $whereClause = ' ( 0 ) ';
813 }
814
815 return $whereClause;
816 }
817
818 public static function group($type,
819 $contactID = NULL,
820 $tableName = 'civicrm_saved_search',
821 $allGroups = NULL,
822 $includedGroups = NULL
823 ) {
824
825 $acls = CRM_ACL_BAO_Cache::build($contactID);
826
827 if (!empty($includedGroups) &&
828 is_array($includedGroups)
829 ) {
830 $ids = $includedGroups;
831 }
832 else {
833 $ids = array();
834 }
835
836 if (!empty($acls)) {
837 $aclKeys = array_keys($acls);
838 $aclKeys = implode(',', $aclKeys);
839
840 $query = "
841 SELECT a.operation, a.object_id
842 FROM civicrm_acl_cache c, civicrm_acl a
843 WHERE c.acl_id = a.id
844 AND a.is_active = 1
845 AND a.object_table = %1
846 AND a.id IN ( $aclKeys )
847 GROUP BY a.operation,a.object_id
848 ORDER BY a.object_id
849 ";
850 $params = array(1 => array($tableName, 'String'));
851 $dao = CRM_Core_DAO::executeQuery($query, $params);
852 while ($dao->fetch()) {
853 if ($dao->object_id) {
854 if (self::matchType($type, $dao->operation)) {
855 $ids[] = $dao->object_id;
856 }
857 }
858 else {
859 // this user has got the permission for all objects of this type
860 // check if the type matches
861 if (self::matchType($type, $dao->operation)) {
862 foreach ($allGroups as $id => $dontCare) {
863 $ids[] = $id;
864 }
865 }
866 break;
867 }
868 }
869 }
870
871 CRM_Utils_Hook::aclGroup($type, $contactID, $tableName, $allGroups, $ids);
872
873 return $ids;
874 }
875
876 static function matchType($type, $operation) {
877 $typeCheck = FALSE;
878 switch ($operation) {
879 case 'All':
880 $typeCheck = TRUE;
881 break;
882
883 case 'View':
884 if ($type == CRM_ACL_API::VIEW) {
885 $typeCheck = TRUE;
886 }
887 break;
888
889 case 'Edit':
890 if ($type == CRM_ACL_API::VIEW || $type == CRM_ACL_API::EDIT) {
891 $typeCheck = TRUE;
892 }
893 break;
894
895 case 'Create':
896 if ($type == CRM_ACL_API::CREATE) {
897 $typeCheck = TRUE;
898 }
899 break;
900
901 case 'Delete':
902 if ($type == CRM_ACL_API::DELETE) {
903 $typeCheck = TRUE;
904 }
905 break;
906
907 case 'Search':
908 if ($type == CRM_ACL_API::SEARCH) {
909 $typeCheck = TRUE;
910 }
911 break;
912 }
913 return $typeCheck;
914 }
915
916 /**
917 * Function to delete ACL records
918 *
919 * @param int $aclId ID of the ACL record to be deleted.
920 *
921 * @access public
922 * @static
923 */
924 static function del($aclId) {
925 // delete all entries from the acl cache
926 CRM_ACL_BAO_Cache::resetCache();
927
928 $acl = new CRM_ACL_DAO_ACL();
929 $acl->id = $aclId;
930 $acl->delete();
931 }
932 }
933