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