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