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