Merge pull request #23781 from civicrm/5.51
[civicrm-core.git] / CRM / Core / Permission.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
19 * This is the basic permission class wrapper
20 */
21class CRM_Core_Permission {
22
23 /**
d09edf64 24 * Static strings used to compose permissions.
6a488035
TO
25 *
26 * @const
27 * @var string
28 */
7da04cde 29 const EDIT_GROUPS = 'edit contacts in ', VIEW_GROUPS = 'view contacts in ';
6a488035
TO
30
31 /**
d09edf64 32 * The various type of permissions.
6a488035
TO
33 *
34 * @var int
35 */
7da04cde 36 const EDIT = 1, VIEW = 2, DELETE = 3, CREATE = 4, SEARCH = 5, ALL = 6, ADMIN = 7;
6a488035 37
085823c1 38 /**
d09edf64 39 * A placeholder permission which always fails.
085823c1
TO
40 */
41 const ALWAYS_DENY_PERMISSION = "*always deny*";
42
43 /**
d09edf64 44 * A placeholder permission which always fails.
085823c1
TO
45 */
46 const ALWAYS_ALLOW_PERMISSION = "*always allow*";
47
6dd18b98 48 /**
d09edf64 49 * Various authentication sources.
6dd18b98
DS
50 *
51 * @var int
52 */
7da04cde 53 const AUTH_SRC_UNKNOWN = 0, AUTH_SRC_CHECKSUM = 1, AUTH_SRC_SITEKEY = 2, AUTH_SRC_LOGIN = 4;
6dd18b98 54
6a488035 55 /**
d09edf64 56 * Get the current permission of this user.
6a488035 57 *
a6c01b45
CW
58 * @return string
59 * the permission of the user (edit or view or null)
6a488035
TO
60 */
61 public static function getPermission() {
62 $config = CRM_Core_Config::singleton();
41f314b6 63 return $config->userPermissionClass->getPermission();
6a488035
TO
64 }
65
66 /**
100fef9d 67 * Given a permission string or array, check for access requirements
6a488035 68 *
9b61e85d
CW
69 * Ex 1: Must have 'access CiviCRM'
70 * (string) 'access CiviCRM'
60ec9f43 71 *
b6e769ac
JM
72 * Ex 2: Must have 'access CiviCRM' and 'access AJAX API'
73 * ['access CiviCRM', 'access AJAX API']
60ec9f43 74 *
b6e769ac 75 * Ex 3: Must have 'access CiviCRM' or 'access AJAX API'
9b61e85d 76 * [
b6e769ac 77 * ['access CiviCRM', 'access AJAX API'],
9b61e85d 78 * ],
60ec9f43 79 *
b6e769ac 80 * Ex 4: Must have 'access CiviCRM' or 'access AJAX API' AND 'access CiviEvent'
9b61e85d 81 * [
b6e769ac 82 * ['access CiviCRM', 'access AJAX API'],
9b61e85d
CW
83 * 'access CiviEvent',
84 * ],
60ec9f43 85 *
9b61e85d
CW
86 * Note that in permissions.php this is keyed by the action eg.
87 * (access Civi || access AJAX) && (access CiviEvent || access CiviContribute)
88 * 'myaction' => [
b6e769ac 89 * ['access CiviCRM', 'access AJAX API'],
9b61e85d
CW
90 * ['access CiviEvent', 'access CiviContribute']
91 * ],
60ec9f43 92 *
9b61e85d
CW
93 * @param string|array $permissions
94 * The permission to check as an array or string -see examples.
60ec9f43 95 *
9b61e85d
CW
96 * @param int $contactId
97 * Contact id to check permissions for. Defaults to current logged-in user.
6a488035 98 *
acb1052e 99 * @return bool
9b61e85d 100 * true if contact has permission(s), else false
6a488035 101 */
18be3201 102 public static function check($permissions, $contactId = NULL) {
60ec9f43 103 $permissions = (array) $permissions;
9b61e85d 104 $userId = CRM_Core_BAO_UFMatch::getUFId($contactId);
60ec9f43 105
18be3201 106 /** @var CRM_Core_Permission_Temp $tempPerm */
59735506
TO
107 $tempPerm = CRM_Core_Config::singleton()->userPermissionTemp;
108
60ec9f43 109 foreach ($permissions as $permission) {
22e263ad 110 if (is_array($permission)) {
60ec9f43 111 foreach ($permission as $orPerm) {
18be3201 112 if (self::check($orPerm, $contactId)) {
60ec9f43 113 //one of our 'or' permissions has succeeded - stop checking this permission
b8a19656 114 return TRUE;
60ec9f43
E
115 }
116 }
117 //none of our our conditions was met
118 return FALSE;
119 }
120 else {
3ae62cab 121 // This is an individual permission
755a1835 122 $impliedPermissions = self::getImpliedPermissionsFor($permission);
123 $impliedPermissions[] = $permission;
124 foreach ($impliedPermissions as $permissionOption) {
125 $granted = CRM_Core_Config::singleton()->userPermissionClass->check($permissionOption, $userId);
126 // Call the permission_check hook to permit dynamic escalation (CRM-19256)
127 CRM_Utils_Hook::permission_check($permissionOption, $granted, $contactId);
128 if ($granted) {
129 break;
130 }
131 }
132
59735506 133 if (
3ae62cab 134 !$granted
59735506
TO
135 && !($tempPerm && $tempPerm->check($permission))
136 ) {
60ec9f43
E
137 //one of our 'and' conditions has not been met
138 return FALSE;
139 }
140 }
141 }
142 return TRUE;
6a488035
TO
143 }
144
dc92f2f8 145 /**
d09edf64 146 * Determine if any one of the permissions strings applies to current user.
dc92f2f8
TO
147 *
148 * @param array $perms
149 * @return bool
150 */
151 public static function checkAnyPerm($perms) {
152 foreach ($perms as $perm) {
153 if (CRM_Core_Permission::check($perm)) {
154 return TRUE;
155 }
156 }
157 return FALSE;
158 }
159
6a488035
TO
160 /**
161 * Given a group/role array, check for access requirements
162 *
6a0b768e
TO
163 * @param array $array
164 * The group/role to check.
6a488035 165 *
acb1052e 166 * @return bool
a6c01b45 167 * true if yes, else false
6a488035 168 */
00be9182 169 public static function checkGroupRole($array) {
6a488035 170 $config = CRM_Core_Config::singleton();
41f314b6 171 return $config->userPermissionClass->checkGroupRole($array);
6a488035
TO
172 }
173
174 /**
d09edf64 175 * Get the permissioned where clause for the user.
6a488035 176 *
6a0b768e
TO
177 * @param int $type
178 * The type of permission needed.
179 * @param array $tables
180 * (reference ) add the tables that are needed for the select clause.
181 * @param array $whereTables
182 * (reference ) add the tables that are needed for the where clause.
6a488035 183 *
a6c01b45
CW
184 * @return string
185 * the group where clause for this user
6a488035
TO
186 */
187 public static function getPermissionedStaticGroupClause($type, &$tables, &$whereTables) {
188 $config = CRM_Core_Config::singleton();
41f314b6 189 return $config->userPermissionClass->getPermissionedStaticGroupClause($type, $tables, $whereTables);
6a488035
TO
190 }
191
192 /**
193 * Get all groups from database, filtered by permissions
194 * for this user
195 *
6a0b768e
TO
196 * @param string $groupType
197 * Type of group(Access/Mailing).
3f8d2862
CW
198 * @param bool $excludeHidden
199 * exclude hidden groups.
6a488035 200 *
6a488035 201 *
a6c01b45
CW
202 * @return array
203 * array reference of all groups.
6a488035
TO
204 */
205 public static function group($groupType, $excludeHidden = TRUE) {
206 $config = CRM_Core_Config::singleton();
41f314b6 207 return $config->userPermissionClass->group($groupType, $excludeHidden);
6a488035
TO
208 }
209
a0ee3941 210 /**
317103ab 211 * @param int $userId
a0ee3941
EM
212 * @return bool
213 */
317103ab 214 public static function customGroupAdmin($userId = NULL) {
6a488035
TO
215 // check if user has all powerful permission
216 // or administer civicrm permission (CRM-1905)
317103ab 217 if (self::check('access all custom data', $userId)) {
6a488035
TO
218 return TRUE;
219 }
220
634e1a1a 221 if (
317103ab 222 self::check('administer Multiple Organizations', $userId) &&
6a488035
TO
223 self::isMultisiteEnabled()
224 ) {
225 return TRUE;
226 }
227
317103ab 228 if (self::check('administer CiviCRM data', $userId)) {
6a488035
TO
229 return TRUE;
230 }
231
232 return FALSE;
233 }
234
a0ee3941
EM
235 /**
236 * @param int $type
237 * @param bool $reset
317103ab 238 * @param int $userId
a0ee3941
EM
239 *
240 * @return array
241 */
317103ab 242 public static function customGroup($type = CRM_Core_Permission::VIEW, $reset = FALSE, $userId = NULL) {
41f314b6 243 $customGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_CustomField', 'custom_group_id',
be2fb01f
CW
244 ['fresh' => $reset]);
245 $defaultGroups = [];
6a488035
TO
246
247 // check if user has all powerful permission
248 // or administer civicrm permission (CRM-1905)
317103ab
CW
249 if (self::customGroupAdmin($userId)) {
250 return array_keys($customGroups);
6a488035
TO
251 }
252
317103ab 253 return CRM_ACL_API::group($type, $userId, 'civicrm_custom_group', $customGroups, $defaultGroups);
6a488035
TO
254 }
255
a0ee3941
EM
256 /**
257 * @param int $type
3fd42bb5 258 * @param string|null $prefix
a0ee3941
EM
259 * @param bool $reset
260 *
261 * @return string
262 */
00be9182 263 public static function customGroupClause($type = CRM_Core_Permission::VIEW, $prefix = NULL, $reset = FALSE) {
6a488035
TO
264 if (self::customGroupAdmin()) {
265 return ' ( 1 ) ';
266 }
267
268 $groups = self::customGroup($type, $reset);
269 if (empty($groups)) {
270 return ' ( 0 ) ';
271 }
272 else {
273 return "{$prefix}id IN ( " . implode(',', $groups) . ' ) ';
274 }
275 }
276
a0ee3941 277 /**
100fef9d 278 * @param int $gid
a0ee3941
EM
279 * @param int $type
280 *
281 * @return bool
282 */
6a488035
TO
283 public static function ufGroupValid($gid, $type = CRM_Core_Permission::VIEW) {
284 if (empty($gid)) {
285 return TRUE;
286 }
287
288 $groups = self::ufGroup($type);
63d76404 289 return !empty($groups) && in_array($gid, $groups);
6a488035
TO
290 }
291
a0ee3941
EM
292 /**
293 * @param int $type
294 *
295 * @return array
296 */
6a488035 297 public static function ufGroup($type = CRM_Core_Permission::VIEW) {
ff4f7744 298 $ufGroups = CRM_Core_PseudoConstant::get('CRM_Core_DAO_UFField', 'uf_group_id');
6a488035
TO
299
300 $allGroups = array_keys($ufGroups);
301
302 // check if user has all powerful permission
303 if (self::check('profile listings and forms')) {
304 return $allGroups;
305 }
306
307 switch ($type) {
308 case CRM_Core_Permission::VIEW:
309 if (self::check('profile view')) {
310 return $allGroups;
311 }
312 break;
313
314 case CRM_Core_Permission::CREATE:
315 if (self::check('profile create')) {
316 return $allGroups;
317 }
318 break;
319
320 case CRM_Core_Permission::EDIT:
321 if (self::check('profile edit')) {
322 return $allGroups;
323 }
324 break;
325
326 case CRM_Core_Permission::SEARCH:
327 if (self::check('profile listings')) {
328 return $allGroups;
329 }
330 break;
331 }
332
333 return CRM_ACL_API::group($type, NULL, 'civicrm_uf_group', $ufGroups);
334 }
335
a0ee3941
EM
336 /**
337 * @param int $type
5e21e0f3 338 * @param string $prefix
a0ee3941
EM
339 * @param bool $returnUFGroupIds
340 *
341 * @return array|string
342 */
00be9182 343 public static function ufGroupClause($type = CRM_Core_Permission::VIEW, $prefix = NULL, $returnUFGroupIds = FALSE) {
6a488035
TO
344 $groups = self::ufGroup($type);
345 if ($returnUFGroupIds) {
346 return $groups;
347 }
348 elseif (empty($groups)) {
349 return ' ( 0 ) ';
350 }
351 else {
352 return "{$prefix}id IN ( " . implode(',', $groups) . ' ) ';
353 }
354 }
355
a0ee3941
EM
356 /**
357 * @param int $type
100fef9d 358 * @param int $eventID
a0ee3941
EM
359 * @param string $context
360 *
361 * @return array|null
362 */
e2d09ab4 363 public static function event($type = CRM_Core_Permission::VIEW, $eventID = NULL, $context = '') {
22e263ad
TO
364 if (!empty($context)) {
365 if (CRM_Core_Permission::check($context)) {
e2d09ab4
EM
366 return TRUE;
367 }
368 }
6a488035 369 $events = CRM_Event_PseudoConstant::event(NULL, TRUE);
be2fb01f 370 $includeEvents = [];
6a488035
TO
371
372 // check if user has all powerful permission
373 if (self::check('register for events')) {
374 $includeEvents = array_keys($events);
375 }
376
377 if ($type == CRM_Core_Permission::VIEW &&
378 self::check('view event info')
379 ) {
380 $includeEvents = array_keys($events);
381 }
382
383 $permissionedEvents = CRM_ACL_API::group($type, NULL, 'civicrm_event', $events, $includeEvents);
384 if (!$eventID) {
385 return $permissionedEvents;
386 }
41f314b6 387 if (!empty($permissionedEvents)) {
2efcf0c2 388 return array_search($eventID, $permissionedEvents) === FALSE ? NULL : $eventID;
41f314b6 389 }
dfa720e7 390 return NULL;
6a488035
TO
391 }
392
a0ee3941
EM
393 /**
394 * @param int $type
395 * @param null $prefix
396 *
397 * @return string
398 */
00be9182 399 public static function eventClause($type = CRM_Core_Permission::VIEW, $prefix = NULL) {
6a488035
TO
400 $events = self::event($type);
401 if (empty($events)) {
402 return ' ( 0 ) ';
403 }
404 else {
405 return "{$prefix}id IN ( " . implode(',', $events) . ' ) ';
406 }
407 }
408
a0ee3941 409 /**
44d17ec8
BS
410 * Checks that component is enabled and optionally that user has basic perm.
411 *
412 * @param string $module
413 * Specifies the name of the CiviCRM component.
a0ee3941 414 * @param bool $checkPermission
44d17ec8
BS
415 * Check not only that module is enabled, but that user has necessary
416 * permission.
417 * @param bool $requireAllCasesPermOnCiviCase
418 * Significant only if $module == CiviCase
419 * Require "access all cases and activities", not just
420 * "access my cases and activities".
a0ee3941
EM
421 *
422 * @return bool
44d17ec8 423 * Access to specified $module is granted.
a0ee3941 424 */
44d17ec8 425 public static function access($module, $checkPermission = TRUE, $requireAllCasesPermOnCiviCase = FALSE) {
e46f73c7 426 if (!CRM_Core_Component::isEnabled($module)) {
6a488035
TO
427 return FALSE;
428 }
429
430 if ($checkPermission) {
44d17ec8
BS
431 switch ($module) {
432 case 'CiviCase':
433 $access_all_cases = CRM_Core_Permission::check("access all cases and activities");
434 $access_my_cases = CRM_Core_Permission::check("access my cases and activities");
435 return $access_all_cases || (!$requireAllCasesPermOnCiviCase && $access_my_cases);
436
437 case 'CiviCampaign':
438 return CRM_Core_Permission::check("administer $module");
439
440 default:
441 return CRM_Core_Permission::check("access $module");
6a488035
TO
442 }
443 }
444
445 return TRUE;
446 }
447
448 /**
d09edf64 449 * Check permissions for delete and edit actions.
6a488035 450 *
6a0b768e
TO
451 * @param string $module
452 * Component name.
453 * @param int $action
454 * Action to be check across component.
6a488035 455 *
77b97be7
EM
456 *
457 * @return bool
458 */
00be9182 459 public static function checkActionPermission($module, $action) {
6a488035
TO
460 //check delete related permissions.
461 if ($action & CRM_Core_Action::DELETE) {
462 $permissionName = "delete in $module";
463 }
464 else {
be2fb01f 465 $editPermissions = [
6a488035
TO
466 'CiviEvent' => 'edit event participants',
467 'CiviMember' => 'edit memberships',
468 'CiviPledge' => 'edit pledges',
469 'CiviContribute' => 'edit contributions',
470 'CiviGrant' => 'edit grants',
471 'CiviMail' => 'access CiviMail',
472 'CiviAuction' => 'add auction items',
be2fb01f 473 ];
9c1bc317 474 $permissionName = $editPermissions[$module] ?? NULL;
6a488035
TO
475 }
476
477 if ($module == 'CiviCase' && !$permissionName) {
478 return CRM_Case_BAO_Case::accessCiviCase();
479 }
480 else {
481 //check for permission.
482 return CRM_Core_Permission::check($permissionName);
483 }
484 }
485
a0ee3941
EM
486 /**
487 * @param $args
488 * @param string $op
489 *
490 * @return bool
491 */
00be9182 492 public static function checkMenu(&$args, $op = 'and') {
6a488035
TO
493 if (!is_array($args)) {
494 return $args;
495 }
496 foreach ($args as $str) {
497 $res = CRM_Core_Permission::check($str);
498 if ($op == 'or' && $res) {
499 return TRUE;
500 }
501 elseif ($op == 'and' && !$res) {
502 return FALSE;
503 }
504 }
505 return ($op == 'or') ? FALSE : TRUE;
506 }
507
a0ee3941
EM
508 /**
509 * @param $item
510 *
511 * @return bool|mixed
512 * @throws Exception
513 */
00be9182 514 public static function checkMenuItem(&$item) {
6a488035
TO
515 if (!array_key_exists('access_callback', $item)) {
516 CRM_Core_Error::backtrace();
79e11805 517 throw new CRM_Core_Exception('Missing Access Callback key in menu item');
6a488035
TO
518 }
519
520 // if component_id is present, ensure it is enabled
3d31a5c6
TO
521 if (isset($item['component_id']) && $item['component_id']) {
522 if (!isset(Civi::$statics[__CLASS__]['componentNameId'])) {
523 Civi::$statics[__CLASS__]['componentNameId'] = array_flip(CRM_Core_Component::getComponentIDs());
524 }
525 $componentName = Civi::$statics[__CLASS__]['componentNameId'][$item['component_id']];
526
6a488035 527 $config = CRM_Core_Config::singleton();
3d31a5c6 528 if (is_array($config->enableComponents) && in_array($componentName, $config->enableComponents)) {
6a488035
TO
529 // continue with process
530 }
531 else {
532 return FALSE;
533 }
534 }
535
536 // the following is imitating drupal 6 code in includes/menu.inc
537 if (empty($item['access_callback']) ||
538 is_numeric($item['access_callback'])
539 ) {
596a8bdf 540 return (bool) $item['access_callback'];
6a488035
TO
541 }
542
543 // check whether the following Ajax requests submitted the right key
544 // FIXME: this should be integrated into ACLs proper
545 if (CRM_Utils_Array::value('page_type', $item) == 3) {
546 if (!CRM_Core_Key::validate($_REQUEST['key'], $item['path'])) {
547 return FALSE;
548 }
549 }
550
551 // check if callback is for checkMenu, if so optimize it
552 if (is_array($item['access_callback']) &&
553 $item['access_callback'][0] == 'CRM_Core_Permission' &&
554 $item['access_callback'][1] == 'checkMenu'
555 ) {
556 $op = CRM_Utils_Array::value(1, $item['access_arguments'], 'and');
557 return self::checkMenu($item['access_arguments'][0], $op);
558 }
559 else {
560 return call_user_func_array($item['access_callback'], $item['access_arguments']);
561 }
562 }
563
a0ee3941
EM
564 /**
565 * @param bool $all
9476d8d1 566 * Include disabled components
221b21b4 567 * @param bool $descriptions
9476d8d1 568 * Whether to return descriptions
a0ee3941
EM
569 *
570 * @return array
571 */
9476d8d1 572 public static function basicPermissions($all = FALSE, $descriptions = FALSE) {
be2fb01f 573 $cacheKey = implode('-', [$all, $descriptions]);
9476d8d1
CW
574 if (empty(Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey])) {
575 Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey] = self::assembleBasicPermissions($all, $descriptions);
221b21b4 576 }
9476d8d1 577 return Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey];
221b21b4
AH
578 }
579
580 /**
581 * @param bool $all
582 * @param bool $descriptions
583 * whether to return descriptions
584 *
585 * @return array
d2b6eac8 586 * @throws \CRM_Core_Exception
221b21b4 587 */
d2b6eac8 588 public static function assembleBasicPermissions($all = FALSE, $descriptions = FALSE): array {
589 $permissions = self::getCoreAndComponentPermissions($all);
221b21b4 590
b4d6a411 591 // Add any permissions defined in hook_civicrm_permission implementations.
1a1100ef 592 $module_permissions = CRM_Core_Config::singleton()->userPermissionClass->getAllModulePermissions(TRUE);
b4d6a411 593 $permissions = array_merge($permissions, $module_permissions);
8c282315 594 if (!$descriptions) {
595 foreach ($permissions as $name => $attr) {
596 $permissions[$name] = array_shift($attr);
597 }
598 }
6a488035
TO
599 return $permissions;
600 }
601
a0ee3941
EM
602 /**
603 * @return array
604 */
00be9182 605 public static function getAnonymousPermissionsWarnings() {
be2fb01f 606 static $permissions = [];
81bb85ea 607 if (empty($permissions)) {
be2fb01f 608 $permissions = [
21dfd5f5 609 'administer CiviCRM',
be2fb01f 610 ];
81bb85ea
AC
611 $components = CRM_Core_Component::getComponents();
612 foreach ($components as $comp) {
613 if (!method_exists($comp, 'getAnonymousPermissionWarnings')) {
614 continue;
615 }
616 $permissions = array_merge($permissions, $comp->getAnonymousPermissionWarnings());
617 }
618 }
619 return $permissions;
620 }
621
a0ee3941
EM
622 /**
623 * @param $anonymous_perms
624 *
625 * @return array
626 */
00be9182 627 public static function validateForPermissionWarnings($anonymous_perms) {
81bb85ea
AC
628 return array_intersect($anonymous_perms, self::getAnonymousPermissionsWarnings());
629 }
630
a0ee3941 631 /**
6793d6a9 632 * Get core permissions.
221b21b4 633 *
a0ee3941
EM
634 * @return array
635 */
8c282315 636 public static function getCorePermissions() {
6a488035 637 $prefix = ts('CiviCRM') . ': ';
be2fb01f
CW
638 $permissions = [
639 'add contacts' => [
221b21b4
AH
640 $prefix . ts('add contacts'),
641 ts('Create a new contact record in CiviCRM'),
be2fb01f
CW
642 ],
643 'view all contacts' => [
221b21b4
AH
644 $prefix . ts('view all contacts'),
645 ts('View ANY CONTACT in the CiviCRM database, export contact info and perform activities such as Send Email, Phone Call, etc.'),
be2fb01f
CW
646 ],
647 'edit all contacts' => [
221b21b4
AH
648 $prefix . ts('edit all contacts'),
649 ts('View, Edit and Delete ANY CONTACT in the CiviCRM database; Create and edit relationships, tags and other info about the contacts'),
be2fb01f
CW
650 ],
651 'view my contact' => [
221b21b4 652 $prefix . ts('view my contact'),
be2fb01f
CW
653 ],
654 'edit my contact' => [
221b21b4 655 $prefix . ts('edit my contact'),
be2fb01f
CW
656 ],
657 'delete contacts' => [
221b21b4 658 $prefix . ts('delete contacts'),
be2fb01f
CW
659 ],
660 'access deleted contacts' => [
221b21b4
AH
661 $prefix . ts('access deleted contacts'),
662 ts('Access contacts in the trash'),
be2fb01f
CW
663 ],
664 'import contacts' => [
221b21b4
AH
665 $prefix . ts('import contacts'),
666 ts('Import contacts and activities'),
be2fb01f
CW
667 ],
668 'import SQL datasource' => [
40bc3c68
TO
669 $prefix . ts('import SQL datasource'),
670 ts('When importing, consume data directly from a SQL datasource'),
be2fb01f
CW
671 ],
672 'edit groups' => [
221b21b4
AH
673 $prefix . ts('edit groups'),
674 ts('Create new groups, edit group settings (e.g. group name, visibility...), delete groups'),
be2fb01f
CW
675 ],
676 'administer CiviCRM' => [
221b21b4
AH
677 $prefix . ts('administer CiviCRM'),
678 ts('Perform all tasks in the Administer CiviCRM control panel and Import Contacts'),
be2fb01f
CW
679 ],
680 'skip IDS check' => [
221b21b4 681 $prefix . ts('skip IDS check'),
d9a37cbc 682 ts('Warning: Give to trusted roles only; this permission has security implications. IDS system is bypassed for users with this permission. Prevents false errors for admin users.'),
be2fb01f
CW
683 ],
684 'access uploaded files' => [
221b21b4
AH
685 $prefix . ts('access uploaded files'),
686 ts('View / download files including images and photos'),
be2fb01f
CW
687 ],
688 'profile listings and forms' => [
221b21b4 689 $prefix . ts('profile listings and forms'),
d9a37cbc 690 ts('Warning: Give to trusted roles only; this permission has privacy implications. Add/edit data in online forms and access public searchable directories.'),
be2fb01f
CW
691 ],
692 'profile listings' => [
221b21b4 693 $prefix . ts('profile listings'),
d9a37cbc 694 ts('Warning: Give to trusted roles only; this permission has privacy implications. Access public searchable directories.'),
be2fb01f
CW
695 ],
696 'profile create' => [
221b21b4 697 $prefix . ts('profile create'),
d9a37cbc 698 ts('Add data in a profile form.'),
be2fb01f
CW
699 ],
700 'profile edit' => [
221b21b4 701 $prefix . ts('profile edit'),
d9a37cbc 702 ts('Edit data in a profile form.'),
be2fb01f
CW
703 ],
704 'profile view' => [
221b21b4 705 $prefix . ts('profile view'),
d9a37cbc 706 ts('View data in a profile.'),
be2fb01f
CW
707 ],
708 'access all custom data' => [
221b21b4
AH
709 $prefix . ts('access all custom data'),
710 ts('View all custom fields regardless of ACL rules'),
be2fb01f
CW
711 ],
712 'view all activities' => [
221b21b4
AH
713 $prefix . ts('view all activities'),
714 ts('View all activities (for visible contacts)'),
be2fb01f
CW
715 ],
716 'delete activities' => [
221b21b4 717 $prefix . ts('Delete activities'),
be2fb01f
CW
718 ],
719 'edit inbound email basic information' => [
ee90a98c
CR
720 $prefix . ts('edit inbound email basic information'),
721 ts('Edit all inbound email activities (for visible contacts) basic information. Content editing not allowed.'),
be2fb01f
CW
722 ],
723 'edit inbound email basic information and content' => [
ee90a98c
CR
724 $prefix . ts('edit inbound email basic information and content'),
725 ts('Edit all inbound email activities (for visible contacts) basic information and content.'),
be2fb01f
CW
726 ],
727 'access CiviCRM' => [
d9a37cbc
H
728 $prefix . ts('access CiviCRM backend and API'),
729 ts('Master control for access to the main CiviCRM backend and API. Give to trusted roles only.'),
be2fb01f
CW
730 ],
731 'access Contact Dashboard' => [
221b21b4
AH
732 $prefix . ts('access Contact Dashboard'),
733 ts('View Contact Dashboard (for themselves and visible contacts)'),
be2fb01f
CW
734 ],
735 'translate CiviCRM' => [
221b21b4
AH
736 $prefix . ts('translate CiviCRM'),
737 ts('Allow User to enable multilingual'),
be2fb01f
CW
738 ],
739 'manage tags' => [
eaaaef83
I
740 $prefix . ts('manage tags'),
741 ts('Create and rename tags'),
be2fb01f
CW
742 ],
743 'administer reserved groups' => [
221b21b4
AH
744 $prefix . ts('administer reserved groups'),
745 ts('Edit and disable Reserved Groups (Needs Edit Groups)'),
be2fb01f
CW
746 ],
747 'administer Tagsets' => [
221b21b4 748 $prefix . ts('administer Tagsets'),
be2fb01f
CW
749 ],
750 'administer reserved tags' => [
221b21b4 751 $prefix . ts('administer reserved tags'),
be2fb01f 752 ],
d76345c9
TO
753 'administer queues' => [
754 $prefix . ts('administer queues'),
755 ts('Initialize, browse, and cancel background processing queues'),
756 // At time of writing, we have specifically omitted the ability to edit fine-grained
757 // data about specific queue-tasks. Tasks are usually defined as PHP callables...
758 // and one should hesitate before allowing open-ended edits of PHP callables.
759 // However, it seems fine for web-admins to browse and cancel these things.
760 ],
be2fb01f 761 'administer dedupe rules' => [
221b21b4
AH
762 $prefix . ts('administer dedupe rules'),
763 ts('Create and edit rules, change the supervised and unsupervised rules'),
be2fb01f
CW
764 ],
765 'merge duplicate contacts' => [
221b21b4
AH
766 $prefix . ts('merge duplicate contacts'),
767 ts('Delete Contacts must also be granted in order for this to work.'),
be2fb01f
CW
768 ],
769 'force merge duplicate contacts' => [
fd630ef9 770 $prefix . ts('force merge duplicate contacts'),
771 ts('Delete Contacts must also be granted in order for this to work.'),
be2fb01f
CW
772 ],
773 'view debug output' => [
221b21b4
AH
774 $prefix . ts('view debug output'),
775 ts('View results of debug and backtrace'),
be2fb01f 776 ],
02d451ab 777
be2fb01f 778 'view all notes' => [
221b21b4
AH
779 $prefix . ts('view all notes'),
780 ts("View notes (for visible contacts) even if they're marked admin only"),
be2fb01f
CW
781 ],
782 'add contact notes' => [
088101a4
O
783 $prefix . ts('add contact notes'),
784 ts("Create notes for contacts"),
be2fb01f
CW
785 ],
786 'access AJAX API' => [
221b21b4
AH
787 $prefix . ts('access AJAX API'),
788 ts('Allow API access even if Access CiviCRM is not granted'),
be2fb01f
CW
789 ],
790 'access contact reference fields' => [
221b21b4
AH
791 $prefix . ts('access contact reference fields'),
792 ts('Allow entering data into contact reference fields'),
be2fb01f
CW
793 ],
794 'create manual batch' => [
221b21b4
AH
795 $prefix . ts('create manual batch'),
796 ts('Create an accounting batch (with Access to CiviContribute and View Own/All Manual Batches)'),
be2fb01f
CW
797 ],
798 'edit own manual batches' => [
221b21b4
AH
799 $prefix . ts('edit own manual batches'),
800 ts('Edit accounting batches created by user'),
be2fb01f
CW
801 ],
802 'edit all manual batches' => [
221b21b4
AH
803 $prefix . ts('edit all manual batches'),
804 ts('Edit all accounting batches'),
be2fb01f
CW
805 ],
806 'close own manual batches' => [
47a98aef 807 $prefix . ts('close own manual batches'),
5ad18cc2 808 ts('Close accounting batches created by user (with Access to CiviContribute)'),
be2fb01f
CW
809 ],
810 'close all manual batches' => [
47a98aef 811 $prefix . ts('close all manual batches'),
5ad18cc2 812 ts('Close all accounting batches (with Access to CiviContribute)'),
be2fb01f
CW
813 ],
814 'reopen own manual batches' => [
47a98aef 815 $prefix . ts('reopen own manual batches'),
5ad18cc2 816 ts('Reopen accounting batches created by user (with Access to CiviContribute)'),
be2fb01f
CW
817 ],
818 'reopen all manual batches' => [
47a98aef 819 $prefix . ts('reopen all manual batches'),
5ad18cc2 820 ts('Reopen all accounting batches (with Access to CiviContribute)'),
be2fb01f
CW
821 ],
822 'view own manual batches' => [
221b21b4
AH
823 $prefix . ts('view own manual batches'),
824 ts('View accounting batches created by user (with Access to CiviContribute)'),
be2fb01f
CW
825 ],
826 'view all manual batches' => [
221b21b4
AH
827 $prefix . ts('view all manual batches'),
828 ts('View all accounting batches (with Access to CiviContribute)'),
be2fb01f
CW
829 ],
830 'delete own manual batches' => [
221b21b4
AH
831 $prefix . ts('delete own manual batches'),
832 ts('Delete accounting batches created by user'),
be2fb01f
CW
833 ],
834 'delete all manual batches' => [
221b21b4
AH
835 $prefix . ts('delete all manual batches'),
836 ts('Delete all accounting batches'),
be2fb01f
CW
837 ],
838 'export own manual batches' => [
221b21b4
AH
839 $prefix . ts('export own manual batches'),
840 ts('Export accounting batches created by user'),
be2fb01f
CW
841 ],
842 'export all manual batches' => [
221b21b4
AH
843 $prefix . ts('export all manual batches'),
844 ts('Export all accounting batches'),
be2fb01f
CW
845 ],
846 'administer payment processors' => [
221b21b4
AH
847 $prefix . ts('administer payment processors'),
848 ts('Add, Update, or Disable Payment Processors'),
be2fb01f 849 ],
ebd92daf
TO
850 'render templates' => [
851 $prefix . ts('render templates'),
852 ts('Render open-ended template content. (Additional constraints may apply to autoloaded records and specific notations.)'),
853 ],
be2fb01f 854 'edit message templates' => [
221b21b4 855 $prefix . ts('edit message templates'),
be2fb01f
CW
856 ],
857 'edit system workflow message templates' => [
40a732a9 858 $prefix . ts('edit system workflow message templates'),
be2fb01f
CW
859 ],
860 'edit user-driven message templates' => [
40a732a9 861 $prefix . ts('edit user-driven message templates'),
be2fb01f
CW
862 ],
863 'view my invoices' => [
a664e7b3 864 $prefix . ts('view my invoices'),
dc6b437a 865 ts('Allow users to view/ download their own invoices'),
be2fb01f
CW
866 ],
867 'edit api keys' => [
d4463076
TO
868 $prefix . ts('edit api keys'),
869 ts('Edit API keys'),
be2fb01f
CW
870 ],
871 'edit own api keys' => [
d4463076
TO
872 $prefix . ts('edit own api keys'),
873 ts('Edit user\'s own API keys'),
be2fb01f
CW
874 ],
875 'send SMS' => [
63483feb
MM
876 $prefix . ts('send SMS'),
877 ts('Send an SMS'),
be2fb01f 878 ],
755a1835 879 'administer CiviCRM system' => [
880 'label' => $prefix . ts('administer CiviCRM System'),
4c85c7b6 881 'description' => ts('Perform all system administration tasks in CiviCRM'),
755a1835 882 ],
883 'administer CiviCRM data' => [
884 'label' => $prefix . ts('administer CiviCRM Data'),
4c85c7b6 885 'description' => ts('Permit altering all restricted data options'),
755a1835 886 ],
ea54c6e5 887 'all CiviCRM permissions and ACLs' => [
888 'label' => $prefix . ts('all CiviCRM permissions and ACLs'),
889 'description' => ts('Administer and use CiviCRM bypassing any other permission or ACL checks and enabling the creation of displays and forms that allow others to bypass checks. This permission should be given out with care'),
890 ],
be2fb01f 891 ];
ce6b4d9b 892 if (self::isMultisiteEnabled()) {
893 // This could arguably be moved to the multisite extension but
894 // within core it does permit editing group-organization records.
895 $permissions['administer Multiple Organizations'] = [
896 'label' => $prefix . ts('administer Multiple Organizations'),
897 'description' => ts('Administer multiple organizations. In practice this allows editing the group organization link'),
898 ];
899 }
6a488035
TO
900 return $permissions;
901 }
902
755a1835 903 /**
904 * Get permissions implied by 'superset' permissions.
905 *
906 * @return array
907 */
ea54c6e5 908 public static function getImpliedAdminPermissions(): array {
755a1835 909 return [
ea54c6e5 910 'administer CiviCRM' => ['implied_permissions' => ['administer CiviCRM system', 'administer CiviCRM data']],
911 'administer CiviCRM data' => ['implied_permissions' => ['edit message templates', 'administer dedupe rules']],
912 'administer CiviCRM system' => ['implied_permissions' => ['edit system workflow message templates']],
755a1835 913 ];
914 }
915
916 /**
917 * Get any super-permissions that imply the given permission.
918 *
919 * @param string $permission
920 *
921 * @return array
922 */
ea54c6e5 923 public static function getImpliedPermissionsFor(string $permission): array {
709672c6 924 if (in_array($permission[0], ['@', '*'], TRUE)) {
925 // Special permissions like '*always deny*' - see DynamicFKAuthorizationTest.
926 // Also '@afform - see AfformUsageTest.
927 return [];
928 }
ea54c6e5 929 $implied = Civi::cache('metadata')->get('implied_permissions', []);
930 if (isset($implied[$permission])) {
931 return $implied[$permission];
932 }
709672c6 933 $implied[$permission] = ['all CiviCRM permissions and ACLs'];
934 foreach (self::getImpliedAdminPermissions() as $key => $details) {
ea54c6e5 935 if (in_array($permission, $details['implied_permissions'] ?? [], TRUE)) {
936 $implied[$permission][] = $key;
755a1835 937 }
938 }
ea54c6e5 939 Civi::cache('metadata')->set('implied_permissions', $implied);
940 return $implied[$permission];
755a1835 941 }
942
bf9a7c0f
ES
943 /**
944 * For each entity provides an array of permissions required for each action
945 *
946 * The action is the array key, possible values:
947 * * create: applies to create (with no id in params)
948 * * update: applies to update, setvalue, create (with id in params)
949 * * get: applies to getcount, getsingle, getvalue and other gets
950 * * delete: applies to delete, replace
951 * * meta: applies to getfields, getoptions, getspec
952 * * default: catch-all for anything not declared
953 *
954 * Note: some APIs declare other actions as well
955 *
956 * Permissions should use arrays for AND and arrays of arrays for OR
1a5a2ade 957 * @see CRM_Core_Permission::check
bf9a7c0f
ES
958 *
959 * @return array of permissions
960 */
961 public static function getEntityActionPermissions() {
be2fb01f 962 $permissions = [];
bf9a7c0f
ES
963 // These are the default permissions - if any entity does not declare permissions for a given action,
964 // (or the entity does not declare permissions at all) - then the action will be used from here
be2fb01f 965 $permissions['default'] = [
bf9a7c0f 966 // applies to getfields, getoptions, etc.
be2fb01f 967 'meta' => ['access CiviCRM'],
bf9a7c0f
ES
968 // catch-all, applies to create, get, delete, etc.
969 // If an entity declares it's own 'default' action it will override this one
be2fb01f
CW
970 'default' => ['administer CiviCRM'],
971 ];
bf9a7c0f
ES
972
973 // Note: Additional permissions in DynamicFKAuthorization
be2fb01f
CW
974 $permissions['attachment'] = [
975 'default' => [
976 ['access CiviCRM', 'access AJAX API'],
977 ],
978 ];
bf9a7c0f
ES
979
980 // Contact permissions
be2fb01f
CW
981 $permissions['contact'] = [
982 'create' => [
bf9a7c0f
ES
983 'access CiviCRM',
984 'add contacts',
be2fb01f
CW
985 ],
986 'delete' => [
bf9a7c0f
ES
987 'access CiviCRM',
988 'delete contacts',
be2fb01f 989 ],
bf9a7c0f 990 // managed by query object
be2fb01f 991 'get' => [],
bf9a7c0f 992 // managed by _civicrm_api3_check_edit_permissions
be2fb01f
CW
993 'update' => [],
994 'getquick' => [
995 ['access CiviCRM', 'access AJAX API'],
996 ],
997 'duplicatecheck' => [
f257308b 998 'access CiviCRM',
be2fb01f 999 ],
9f8c8b7a 1000 'merge' => ['merge duplicate contacts'],
be2fb01f 1001 ];
bf9a7c0f 1002
cc477693 1003 $permissions['dedupe'] = [
1004 'getduplicates' => ['access CiviCRM'],
3ea6ec7d 1005 'getstatistics' => ['access CiviCRM'],
cc477693 1006 ];
1007
bf9a7c0f 1008 // CRM-16963 - Permissions for country.
be2fb01f
CW
1009 $permissions['country'] = [
1010 'get' => [
bf9a7c0f 1011 'access CiviCRM',
be2fb01f
CW
1012 ],
1013 'default' => [
bf9a7c0f 1014 'administer CiviCRM',
be2fb01f
CW
1015 ],
1016 ];
bf9a7c0f
ES
1017
1018 // Contact-related data permissions.
be2fb01f 1019 $permissions['address'] = [
bf9a7c0f
ES
1020 // get is managed by BAO::addSelectWhereClause
1021 // create/delete are managed by _civicrm_api3_check_edit_permissions
be2fb01f
CW
1022 'default' => [],
1023 ];
bf9a7c0f
ES
1024 $permissions['email'] = $permissions['address'];
1025 $permissions['phone'] = $permissions['address'];
1026 $permissions['website'] = $permissions['address'];
1027 $permissions['im'] = $permissions['address'];
1028 $permissions['open_i_d'] = $permissions['address'];
1029
1030 // Also managed by ACLs - CRM-19448
be2fb01f 1031 $permissions['entity_tag'] = ['default' => []];
bf9a7c0f
ES
1032 $permissions['note'] = $permissions['entity_tag'];
1033
1034 // Allow non-admins to get and create tags to support tagset widget
1035 // Delete is still reserved for admins
be2fb01f
CW
1036 $permissions['tag'] = [
1037 'get' => ['access CiviCRM'],
1038 'create' => ['access CiviCRM'],
1039 'update' => ['access CiviCRM'],
1040 ];
bf9a7c0f
ES
1041
1042 //relationship permissions
be2fb01f 1043 $permissions['relationship'] = [
bf9a7c0f 1044 // get is managed by BAO::addSelectWhereClause
be2fb01f
CW
1045 'get' => [],
1046 'delete' => [
bf9a7c0f
ES
1047 'access CiviCRM',
1048 'edit all contacts',
be2fb01f
CW
1049 ],
1050 'default' => [
bf9a7c0f
ES
1051 'access CiviCRM',
1052 'edit all contacts',
be2fb01f
CW
1053 ],
1054 ];
962e14bc
CW
1055 // Readonly relationship_cache table
1056 $permissions['relationship_cache'] = [
1057 // get is managed by BAO::addSelectWhereClause
1058 'get' => [],
1059 ];
bf9a7c0f
ES
1060
1061 // CRM-17741 - Permissions for RelationshipType.
be2fb01f
CW
1062 $permissions['relationship_type'] = [
1063 'get' => [
bf9a7c0f 1064 'access CiviCRM',
be2fb01f
CW
1065 ],
1066 'default' => [
bf9a7c0f 1067 'administer CiviCRM',
be2fb01f
CW
1068 ],
1069 ];
bf9a7c0f
ES
1070
1071 // Activity permissions
be2fb01f
CW
1072 $permissions['activity'] = [
1073 'delete' => [
bf9a7c0f
ES
1074 'access CiviCRM',
1075 'delete activities',
be2fb01f
CW
1076 ],
1077 'get' => [
bf9a7c0f
ES
1078 'access CiviCRM',
1079 // Note that view all activities is also required within the api
1080 // if the id is not passed in. Where the id is passed in the activity
1081 // specific check functions are used and tested.
be2fb01f
CW
1082 ],
1083 'default' => [
bf9a7c0f
ES
1084 'access CiviCRM',
1085 'view all activities',
be2fb01f
CW
1086 ],
1087 ];
cdacd6ab 1088 $permissions['activity_contact'] = $permissions['activity'];
bf9a7c0f
ES
1089
1090 // Case permissions
be2fb01f
CW
1091 $permissions['case'] = [
1092 'create' => [
bf9a7c0f
ES
1093 'access CiviCRM',
1094 'add cases',
be2fb01f
CW
1095 ],
1096 'delete' => [
bf9a7c0f
ES
1097 'access CiviCRM',
1098 'delete in CiviCase',
be2fb01f
CW
1099 ],
1100 'restore' => [
8572e6de 1101 'administer CiviCase',
be2fb01f
CW
1102 ],
1103 'merge' => [
a6bc7218 1104 'administer CiviCase',
be2fb01f
CW
1105 ],
1106 'default' => [
bf9a7c0f 1107 // At minimum the user needs one of the following. Finer-grained access is controlled by CRM_Case_BAO_Case::addSelectWhereClause
be2fb01f
CW
1108 ['access my cases and activities', 'access all cases and activities'],
1109 ],
1110 ];
bf9a7c0f 1111 $permissions['case_contact'] = $permissions['case'];
7b52581f 1112 $permissions['case_activity'] = $permissions['case'];
bf9a7c0f 1113
be2fb01f
CW
1114 $permissions['case_type'] = [
1115 'default' => ['administer CiviCase'],
1116 'get' => [
bf9a7c0f 1117 // nested array = OR
be2fb01f
CW
1118 ['access my cases and activities', 'access all cases and activities'],
1119 ],
1120 ];
bf9a7c0f
ES
1121
1122 // Campaign permissions
be2fb01f
CW
1123 $permissions['campaign'] = [
1124 'get' => ['access CiviCRM'],
1125 'default' => [
bf9a7c0f 1126 // nested array = OR
be2fb01f
CW
1127 ['administer CiviCampaign', 'manage campaign'],
1128 ],
1129 ];
bf9a7c0f
ES
1130 $permissions['survey'] = $permissions['campaign'];
1131
1132 // Financial permissions
be2fb01f
CW
1133 $permissions['contribution'] = [
1134 'get' => [
bf9a7c0f
ES
1135 'access CiviCRM',
1136 'access CiviContribute',
be2fb01f
CW
1137 ],
1138 'delete' => [
bf9a7c0f
ES
1139 'access CiviCRM',
1140 'access CiviContribute',
1141 'delete in CiviContribute',
be2fb01f
CW
1142 ],
1143 'completetransaction' => [
bf9a7c0f 1144 'edit contributions',
be2fb01f
CW
1145 ],
1146 'default' => [
bf9a7c0f
ES
1147 'access CiviCRM',
1148 'access CiviContribute',
1149 'edit contributions',
be2fb01f
CW
1150 ],
1151 ];
bf9a7c0f 1152 $permissions['line_item'] = $permissions['contribution'];
7e49aa93 1153 $permissions['product'] = $permissions['contribution'];
bf9a7c0f 1154
ee73f136 1155 $permissions['financial_item'] = $permissions['contribution'];
87e130bb
EM
1156 $permissions['financial_type']['get'] = $permissions['contribution']['get'];
1157 $permissions['entity_financial_account']['get'] = $permissions['contribution']['get'];
1158 $permissions['financial_account']['get'] = $permissions['contribution']['get'];
6596faec 1159 $permissions['financial_trxn']['get'] = $permissions['contribution']['get'];
ee73f136 1160
bf9a7c0f 1161 // Payment permissions
be2fb01f
CW
1162 $permissions['payment'] = [
1163 'get' => [
bf9a7c0f
ES
1164 'access CiviCRM',
1165 'access CiviContribute',
be2fb01f
CW
1166 ],
1167 'delete' => [
bf9a7c0f
ES
1168 'access CiviCRM',
1169 'access CiviContribute',
1170 'delete in CiviContribute',
be2fb01f
CW
1171 ],
1172 'cancel' => [
bf9a7c0f
ES
1173 'access CiviCRM',
1174 'access CiviContribute',
1175 'edit contributions',
be2fb01f
CW
1176 ],
1177 'create' => [
bf9a7c0f
ES
1178 'access CiviCRM',
1179 'access CiviContribute',
1180 'edit contributions',
be2fb01f
CW
1181 ],
1182 'default' => [
bf9a7c0f
ES
1183 'access CiviCRM',
1184 'access CiviContribute',
1185 'edit contributions',
be2fb01f
CW
1186 ],
1187 ];
e4124a88 1188 $permissions['contribution_recur'] = $permissions['payment'];
bf9a7c0f
ES
1189
1190 // Custom field permissions
be2fb01f
CW
1191 $permissions['custom_field'] = [
1192 'default' => [
bf9a7c0f
ES
1193 'administer CiviCRM',
1194 'access all custom data',
be2fb01f
CW
1195 ],
1196 ];
bf9a7c0f
ES
1197 $permissions['custom_group'] = $permissions['custom_field'];
1198
1199 // Event permissions
be2fb01f
CW
1200 $permissions['event'] = [
1201 'create' => [
bf9a7c0f
ES
1202 'access CiviCRM',
1203 'access CiviEvent',
1204 'edit all events',
be2fb01f
CW
1205 ],
1206 'delete' => [
bf9a7c0f
ES
1207 'access CiviCRM',
1208 'access CiviEvent',
1209 'delete in CiviEvent',
be2fb01f
CW
1210 ],
1211 'get' => [
bf9a7c0f
ES
1212 'access CiviCRM',
1213 'access CiviEvent',
1214 'view event info',
be2fb01f
CW
1215 ],
1216 'update' => [
bf9a7c0f
ES
1217 'access CiviCRM',
1218 'access CiviEvent',
1219 'edit all events',
be2fb01f
CW
1220 ],
1221 ];
170af518 1222 // Exception refers to dedupe_exception.
1223 $permissions['exception'] = [
1224 'default' => ['merge duplicate contacts'],
1225 ];
5654496c 1226
418ffc5b 1227 $permissions['job'] = [
1228 'process_batch_merge' => ['merge duplicate contacts'],
1229 ];
5654496c 1230 $permissions['rule_group']['get'] = [['merge duplicate contacts', 'administer CiviCRM']];
bf9a7c0f
ES
1231 // Loc block is only used for events
1232 $permissions['loc_block'] = $permissions['event'];
1233
be2fb01f
CW
1234 $permissions['state_province'] = [
1235 'get' => [
fc2d1728 1236 'access CiviCRM',
be2fb01f
CW
1237 ],
1238 ];
fc2d1728 1239
bf9a7c0f 1240 // Price sets are shared by several components, user needs access to at least one of them
be2fb01f
CW
1241 $permissions['price_set'] = [
1242 'default' => [
1243 ['access CiviEvent', 'access CiviContribute', 'access CiviMember'],
1244 ],
1245 'get' => [
1246 ['access CiviCRM', 'view event info', 'make online contributions'],
1247 ],
1248 ];
bf9a7c0f
ES
1249
1250 // File permissions
be2fb01f
CW
1251 $permissions['file'] = [
1252 'default' => [
bf9a7c0f
ES
1253 'access CiviCRM',
1254 'access uploaded files',
be2fb01f
CW
1255 ],
1256 ];
bf9a7c0f
ES
1257 $permissions['files_by_entity'] = $permissions['file'];
1258
1259 // Group permissions
be2fb01f
CW
1260 $permissions['group'] = [
1261 'get' => [
bf9a7c0f 1262 'access CiviCRM',
be2fb01f
CW
1263 ],
1264 'default' => [
bf9a7c0f
ES
1265 'access CiviCRM',
1266 'edit groups',
be2fb01f
CW
1267 ],
1268 ];
bf9a7c0f
ES
1269
1270 $permissions['group_nesting'] = $permissions['group'];
1271 $permissions['group_organization'] = $permissions['group'];
1272
1273 //Group Contact permission
be2fb01f
CW
1274 $permissions['group_contact'] = [
1275 'get' => [
bf9a7c0f 1276 'access CiviCRM',
be2fb01f
CW
1277 ],
1278 'default' => [
bf9a7c0f
ES
1279 'access CiviCRM',
1280 'edit all contacts',
be2fb01f
CW
1281 ],
1282 ];
bf9a7c0f
ES
1283
1284 // CiviMail Permissions
be2fb01f 1285 $civiMailBasePerms = [
bf9a7c0f
ES
1286 // To get/preview/update, one must have least one of these perms:
1287 // Mailing API implementations enforce nuances of create/approve/schedule permissions.
1288 'access CiviMail',
1289 'create mailings',
1290 'schedule mailings',
1291 'approve mailings',
be2fb01f
CW
1292 ];
1293 $permissions['mailing'] = [
1294 'get' => [
bf9a7c0f
ES
1295 'access CiviCRM',
1296 $civiMailBasePerms,
be2fb01f
CW
1297 ],
1298 'delete' => [
bf9a7c0f
ES
1299 'access CiviCRM',
1300 $civiMailBasePerms,
1301 'delete in CiviMail',
be2fb01f
CW
1302 ],
1303 'submit' => [
bf9a7c0f 1304 'access CiviCRM',
be2fb01f
CW
1305 ['access CiviMail', 'schedule mailings'],
1306 ],
1307 'default' => [
bf9a7c0f
ES
1308 'access CiviCRM',
1309 $civiMailBasePerms,
be2fb01f
CW
1310 ],
1311 ];
bf9a7c0f
ES
1312 $permissions['mailing_group'] = $permissions['mailing'];
1313 $permissions['mailing_job'] = $permissions['mailing'];
1314 $permissions['mailing_recipients'] = $permissions['mailing'];
1315
be2fb01f
CW
1316 $permissions['mailing_a_b'] = [
1317 'get' => [
bf9a7c0f
ES
1318 'access CiviCRM',
1319 'access CiviMail',
be2fb01f
CW
1320 ],
1321 'delete' => [
bf9a7c0f
ES
1322 'access CiviCRM',
1323 'access CiviMail',
1324 'delete in CiviMail',
be2fb01f
CW
1325 ],
1326 'submit' => [
bf9a7c0f 1327 'access CiviCRM',
be2fb01f
CW
1328 ['access CiviMail', 'schedule mailings'],
1329 ],
1330 'default' => [
bf9a7c0f
ES
1331 'access CiviCRM',
1332 'access CiviMail',
be2fb01f
CW
1333 ],
1334 ];
bf9a7c0f
ES
1335
1336 // Membership permissions
be2fb01f
CW
1337 $permissions['membership'] = [
1338 'get' => [
bf9a7c0f
ES
1339 'access CiviCRM',
1340 'access CiviMember',
be2fb01f
CW
1341 ],
1342 'delete' => [
bf9a7c0f
ES
1343 'access CiviCRM',
1344 'access CiviMember',
1345 'delete in CiviMember',
be2fb01f
CW
1346 ],
1347 'default' => [
bf9a7c0f
ES
1348 'access CiviCRM',
1349 'access CiviMember',
1350 'edit memberships',
be2fb01f
CW
1351 ],
1352 ];
bf9a7c0f
ES
1353 $permissions['membership_status'] = $permissions['membership'];
1354 $permissions['membership_type'] = $permissions['membership'];
be2fb01f
CW
1355 $permissions['membership_payment'] = [
1356 'create' => [
bf9a7c0f
ES
1357 'access CiviCRM',
1358 'access CiviMember',
1359 'edit memberships',
1360 'access CiviContribute',
1361 'edit contributions',
be2fb01f
CW
1362 ],
1363 'delete' => [
bf9a7c0f
ES
1364 'access CiviCRM',
1365 'access CiviMember',
1366 'delete in CiviMember',
1367 'access CiviContribute',
1368 'delete in CiviContribute',
be2fb01f
CW
1369 ],
1370 'get' => [
bf9a7c0f
ES
1371 'access CiviCRM',
1372 'access CiviMember',
1373 'access CiviContribute',
be2fb01f
CW
1374 ],
1375 'update' => [
bf9a7c0f
ES
1376 'access CiviCRM',
1377 'access CiviMember',
1378 'edit memberships',
1379 'access CiviContribute',
1380 'edit contributions',
be2fb01f
CW
1381 ],
1382 ];
bf9a7c0f
ES
1383
1384 // Participant permissions
be2fb01f
CW
1385 $permissions['participant'] = [
1386 'create' => [
bf9a7c0f
ES
1387 'access CiviCRM',
1388 'access CiviEvent',
1389 'register for events',
be2fb01f
CW
1390 ],
1391 'delete' => [
bf9a7c0f
ES
1392 'access CiviCRM',
1393 'access CiviEvent',
1394 'edit event participants',
be2fb01f
CW
1395 ],
1396 'get' => [
bf9a7c0f
ES
1397 'access CiviCRM',
1398 'access CiviEvent',
1399 'view event participants',
be2fb01f
CW
1400 ],
1401 'update' => [
bf9a7c0f
ES
1402 'access CiviCRM',
1403 'access CiviEvent',
1404 'edit event participants',
be2fb01f
CW
1405 ],
1406 ];
1407 $permissions['participant_payment'] = [
1408 'create' => [
bf9a7c0f
ES
1409 'access CiviCRM',
1410 'access CiviEvent',
1411 'register for events',
1412 'access CiviContribute',
1413 'edit contributions',
be2fb01f
CW
1414 ],
1415 'delete' => [
bf9a7c0f
ES
1416 'access CiviCRM',
1417 'access CiviEvent',
1418 'edit event participants',
1419 'access CiviContribute',
1420 'delete in CiviContribute',
be2fb01f
CW
1421 ],
1422 'get' => [
bf9a7c0f
ES
1423 'access CiviCRM',
1424 'access CiviEvent',
1425 'view event participants',
1426 'access CiviContribute',
be2fb01f
CW
1427 ],
1428 'update' => [
bf9a7c0f
ES
1429 'access CiviCRM',
1430 'access CiviEvent',
1431 'edit event participants',
1432 'access CiviContribute',
1433 'edit contributions',
be2fb01f
CW
1434 ],
1435 ];
bf9a7c0f
ES
1436
1437 // Pledge permissions
be2fb01f
CW
1438 $permissions['pledge'] = [
1439 'create' => [
bf9a7c0f
ES
1440 'access CiviCRM',
1441 'access CiviPledge',
1442 'edit pledges',
be2fb01f
CW
1443 ],
1444 'delete' => [
bf9a7c0f
ES
1445 'access CiviCRM',
1446 'access CiviPledge',
1447 'delete in CiviPledge',
be2fb01f
CW
1448 ],
1449 'get' => [
bf9a7c0f
ES
1450 'access CiviCRM',
1451 'access CiviPledge',
be2fb01f
CW
1452 ],
1453 'update' => [
bf9a7c0f
ES
1454 'access CiviCRM',
1455 'access CiviPledge',
1456 'edit pledges',
be2fb01f
CW
1457 ],
1458 ];
bf9a7c0f
ES
1459
1460 //CRM-16777: Disable schedule reminder for user that have 'edit all events' and 'administer CiviCRM' permission.
be2fb01f
CW
1461 $permissions['action_schedule'] = [
1462 'update' => [
1463 [
bf9a7c0f
ES
1464 'access CiviCRM',
1465 'edit all events',
be2fb01f
CW
1466 ],
1467 ],
1468 ];
bf9a7c0f 1469
be2fb01f
CW
1470 $permissions['pledge_payment'] = [
1471 'create' => [
bf9a7c0f
ES
1472 'access CiviCRM',
1473 'access CiviPledge',
1474 'edit pledges',
1475 'access CiviContribute',
1476 'edit contributions',
be2fb01f
CW
1477 ],
1478 'delete' => [
bf9a7c0f
ES
1479 'access CiviCRM',
1480 'access CiviPledge',
1481 'delete in CiviPledge',
1482 'access CiviContribute',
1483 'delete in CiviContribute',
be2fb01f
CW
1484 ],
1485 'get' => [
bf9a7c0f
ES
1486 'access CiviCRM',
1487 'access CiviPledge',
1488 'access CiviContribute',
be2fb01f
CW
1489 ],
1490 'update' => [
bf9a7c0f
ES
1491 'access CiviCRM',
1492 'access CiviPledge',
1493 'edit pledges',
1494 'access CiviContribute',
1495 'edit contributions',
be2fb01f
CW
1496 ],
1497 ];
bf9a7c0f 1498
dfcf5ba2
CW
1499 // Dashboard permissions
1500 $permissions['dashboard'] = [
1501 'get' => [
1502 'access CiviCRM',
1503 ],
1504 ];
1505 $permissions['dashboard_contact'] = [
1506 'default' => [
1507 'access CiviCRM',
1508 ],
1509 ];
1510
9ac56a77
CW
1511 $permissions['saved_search'] = [
1512 'default' => ['administer CiviCRM data'],
1513 ];
1514
bf9a7c0f 1515 // Profile permissions
be2fb01f 1516 $permissions['profile'] = [
518fa0ee
SL
1517 // the profile will take care of this
1518 'get' => [],
be2fb01f 1519 ];
bf9a7c0f 1520
be2fb01f
CW
1521 $permissions['uf_group'] = [
1522 'create' => [
bf9a7c0f 1523 'access CiviCRM',
be2fb01f 1524 [
bf9a7c0f
ES
1525 'administer CiviCRM',
1526 'manage event profiles',
be2fb01f
CW
1527 ],
1528 ],
1529 'get' => [
bf9a7c0f 1530 'access CiviCRM',
be2fb01f
CW
1531 ],
1532 'update' => [
bf9a7c0f 1533 'access CiviCRM',
be2fb01f 1534 [
bf9a7c0f
ES
1535 'administer CiviCRM',
1536 'manage event profiles',
be2fb01f
CW
1537 ],
1538 ],
1539 ];
bf9a7c0f 1540 $permissions['uf_field'] = $permissions['uf_join'] = $permissions['uf_group'];
be2fb01f 1541 $permissions['uf_field']['delete'] = [
bf9a7c0f 1542 'access CiviCRM',
be2fb01f 1543 [
bf9a7c0f
ES
1544 'administer CiviCRM',
1545 'manage event profiles',
be2fb01f
CW
1546 ],
1547 ];
bf9a7c0f
ES
1548 $permissions['option_value'] = $permissions['uf_group'];
1549 $permissions['option_group'] = $permissions['option_value'];
1550
e36f7ee1
EM
1551 // User Job permissions - we access these using acls on the get action.
1552 // For create it probably makes sense (at least initially) to be stricter
1553 // as the forms doing the work can set the permission check to FALSE.
1554 $permissions['user_job'] = [
1555 'get' => [
1556 'access CiviCRM',
1557 ],
1558 'default' => [
1559 'administer CiviCRM',
1560 ],
1561 ];
1562
be2fb01f
CW
1563 $permissions['custom_value'] = [
1564 'gettree' => ['access CiviCRM'],
1565 ];
f26fa703 1566
be2fb01f
CW
1567 $permissions['message_template'] = [
1568 'get' => ['access CiviCRM'],
1569 'create' => [['edit message templates', 'edit user-driven message templates', 'edit system workflow message templates']],
1570 'update' => [['edit message templates', 'edit user-driven message templates', 'edit system workflow message templates']],
1571 ];
4341efe4
JV
1572
1573 $permissions['report_template']['update'] = 'save Report Criteria';
1574 $permissions['report_template']['create'] = 'save Report Criteria';
bf9a7c0f
ES
1575 return $permissions;
1576 }
1577
1578 /**
1579 * Translate an unknown action to a canonical form.
1580 *
1581 * @param string $action
1582 *
1583 * @return string
1584 * the standardised action name
1585 */
1586 public static function getGenericAction($action) {
1587 $snippet = substr($action, 0, 3);
1588 if ($action == 'replace' || $snippet == 'del') {
1589 // 'Replace' is a combination of get+create+update+delete; however, the permissions
1590 // on each of those will be tested separately at runtime. This is just a sniff-test
1591 // based on the heuristic that 'delete' tends to be the most closely guarded
1592 // of the necessary permissions.
1593 $action = 'delete';
1594 }
1595 elseif ($action == 'setvalue' || $snippet == 'upd') {
1596 $action = 'update';
1597 }
1598 elseif ($action == 'getfields' || $action == 'getfield' || $action == 'getspec' || $action == 'getoptions') {
1599 $action = 'meta';
1600 }
1601 elseif ($snippet == 'get') {
1602 $action = 'get';
1603 }
1604 return $action;
1605 }
1606
6a488035 1607 /**
d09edf64 1608 * Validate user permission across.
6a488035
TO
1609 * edit or view or with supportable acls.
1610 *
acb1052e
WA
1611 * @return bool
1612 */
00be9182 1613 public static function giveMeAllACLs() {
6a488035
TO
1614 if (CRM_Core_Permission::check('view all contacts') ||
1615 CRM_Core_Permission::check('edit all contacts')
1616 ) {
1617 return TRUE;
1618 }
1619
1620 $session = CRM_Core_Session::singleton();
1621 $contactID = $session->get('userID');
1622
6a488035
TO
1623 //check for acl.
1624 $aclPermission = self::getPermission();
be2fb01f 1625 if (in_array($aclPermission, [
6a488035 1626 CRM_Core_Permission::EDIT,
41f314b6 1627 CRM_Core_Permission::VIEW,
be2fb01f 1628 ])
41f314b6 1629 ) {
6a488035
TO
1630 return TRUE;
1631 }
1632
1633 // run acl where hook and see if the user is supplying an ACL clause
1634 // that is not false
be2fb01f 1635 $tables = $whereTables = [];
6a488035
TO
1636 $where = NULL;
1637
1638 CRM_Utils_Hook::aclWhereClause(CRM_Core_Permission::VIEW,
1639 $tables, $whereTables,
1640 $contactID, $where
1641 );
1642 return empty($whereTables) ? FALSE : TRUE;
1643 }
1644
1645 /**
100fef9d 1646 * Get component name from given permission.
6a488035 1647 *
41f314b6 1648 * @param string $permission
6a488035 1649 *
76e7a76c
CW
1650 * @return null|string
1651 * the name of component.
6a488035 1652 */
00be9182 1653 public static function getComponentName($permission) {
6a488035
TO
1654 $componentName = NULL;
1655 $permission = trim($permission);
1656 if (empty($permission)) {
1657 return $componentName;
1658 }
1659
be2fb01f 1660 static $allCompPermissions = [];
6a488035
TO
1661 if (empty($allCompPermissions)) {
1662 $components = CRM_Core_Component::getComponents();
1663 foreach ($components as $name => $comp) {
33777e4a
PJ
1664 //get all permissions of each components unconditionally
1665 $allCompPermissions[$name] = $comp->getPermissions(TRUE);
6a488035
TO
1666 }
1667 }
1668
1669 if (is_array($allCompPermissions)) {
1670 foreach ($allCompPermissions as $name => $permissions) {
b9021475 1671 if (array_key_exists($permission, $permissions)) {
6a488035
TO
1672 $componentName = $name;
1673 break;
1674 }
1675 }
1676 }
1677
1678 return $componentName;
1679 }
1680
1681 /**
d09edf64 1682 * Get all the contact emails for users that have a specific permission.
6a488035 1683 *
6a0b768e
TO
1684 * @param string $permissionName
1685 * Name of the permission we are interested in.
6a488035 1686 *
a6c01b45
CW
1687 * @return string
1688 * a comma separated list of email addresses
6a488035
TO
1689 */
1690 public static function permissionEmails($permissionName) {
1691 $config = CRM_Core_Config::singleton();
41f314b6 1692 return $config->userPermissionClass->permissionEmails($permissionName);
6a488035
TO
1693 }
1694
1695 /**
d09edf64 1696 * Get all the contact emails for users that have a specific role.
6a488035 1697 *
6a0b768e
TO
1698 * @param string $roleName
1699 * Name of the role we are interested in.
6a488035 1700 *
a6c01b45
CW
1701 * @return string
1702 * a comma separated list of email addresses
6a488035
TO
1703 */
1704 public static function roleEmails($roleName) {
1705 $config = CRM_Core_Config::singleton();
41f314b6 1706 return $config->userRoleClass->roleEmails($roleName);
6a488035
TO
1707 }
1708
a0ee3941
EM
1709 /**
1710 * @return bool
1711 */
00be9182 1712 public static function isMultisiteEnabled() {
63d76404 1713 return (bool) Civi::settings()->get('is_enabled');
6a488035 1714 }
96025800 1715
dc6b437a
GC
1716 /**
1717 * Verify if the user has permission to get the invoice.
1718 *
1719 * @return bool
1720 * TRUE if the user has download all invoices permission or download my
1721 * invoices permission and the invoice author is the current user.
1722 */
1723 public static function checkDownloadInvoice() {
4cfd4f45 1724 $cid = CRM_Core_Session::getLoggedInContactID();
dc6b437a
GC
1725 if (CRM_Core_Permission::check('access CiviContribute') ||
1726 (CRM_Core_Permission::check('view my invoices') && $_GET['cid'] == $cid)
1727 ) {
1728 return TRUE;
1729 }
1730 return FALSE;
1731 }
1732
b4d6a411 1733 /**
d2b6eac8 1734 * Get permissions for components.
1735 *
b4d6a411 1736 * @param bool $includeDisabled
1737 *
1738 * @return array
1739 * @throws \CRM_Core_Exception
1740 */
1741 protected static function getComponentPermissions(bool $includeDisabled): array {
1742 if (!$includeDisabled) {
1743 $components = CRM_Core_Component::getEnabledComponents();
1744 }
1745 else {
1746 $components = CRM_Core_Component::getComponents();
1747 }
1748
1749 $permissions = [];
1750 foreach ($components as $comp) {
1751 $perm = $comp->getPermissions($includeDisabled, TRUE);
1752 if ($perm) {
1753 $info = $comp->getInfo();
1754 foreach ($perm as $p => $attr) {
1755
1756 if (!is_array($attr)) {
1757 $attr = [$attr];
1758 }
1759
1760 $attr[0] = $info['translatedName'] . ': ' . $attr[0];
1761 $permissions[$p] = $attr;
1762 }
1763 }
1764 }
1765 return $permissions;
1766 }
1767
d2b6eac8 1768 /**
1769 * Get permissions for core functionality and for that of core components.
1770 *
1771 * @param bool $all
1772 *
1773 * @return array
1774 * @throws \CRM_Core_Exception
1775 */
1776 protected static function getCoreAndComponentPermissions(bool $all): array {
1777 $permissions = self::getCorePermissions();
1778 $permissions = array_merge($permissions, self::getComponentPermissions($all));
ea54c6e5 1779 $permissions['all CiviCRM permissions and ACLs']['implied_permissions'] = array_keys($permissions);
d2b6eac8 1780 return $permissions;
1781 }
1782
6a488035 1783}