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