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