Merge pull request #13926 from pradpnayak/NoticeErrorProfile
[civicrm-core.git] / tests / phpunit / api / v3 / ACLPermissionTest.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
2fe49090 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
6a488035
TO
28/**
29 * This class is intended to test ACL permission using the multisite module
30 *
7884d958 31 * @package CiviCRM_APIv3
32 * @subpackage API_Contact
acb109b7 33 * @group headless
6a488035 34 */
6a488035 35class api_v3_ACLPermissionTest extends CiviUnitTestCase {
2af6f0c0 36
37 use CRMTraits_ACL_PermissionTrait;
38
4e420887 39 protected $_apiversion = 3;
4e420887 40 public $DBResetRequired = FALSE;
430ae6dd
TO
41 protected $_entity;
42
00be9182 43 public function setUp() {
6a488035
TO
44 parent::setUp();
45 $baoObj = new CRM_Core_DAO();
ff3833b0 46 $baoObj->createTestObject('CRM_Pledge_BAO_Pledge', [], 1, 0);
47 $baoObj->createTestObject('CRM_Core_BAO_Phone', [], 1, 0);
5e8daa54 48 $this->prepareForACLs();
6a488035 49 }
7884d958 50
51 /**
52 * (non-PHPdoc)
53 * @see CiviUnitTestCase::tearDown()
54 */
00be9182 55 public function tearDown() {
5e8daa54 56 $this->cleanUpAfterACLs();
ff3833b0 57 $tablesToTruncate = [
7884d958 58 'civicrm_contact',
ae4bb4c9
EM
59 'civicrm_group_contact',
60 'civicrm_group',
61 'civicrm_acl',
62 'civicrm_acl_cache',
63 'civicrm_acl_entity_role',
64 'civicrm_acl_contact_cache',
65 'civicrm_contribution',
66 'civicrm_participant',
225d474b 67 'civicrm_uf_match',
bbd2743b 68 'civicrm_activity',
69 'civicrm_activity_contact',
c6835264
CW
70 'civicrm_note',
71 'civicrm_entity_tag',
72 'civicrm_tag',
ff3833b0 73 ];
6a488035 74 $this->quickCleanup($tablesToTruncate);
6a488035 75 }
7884d958 76
77 /**
eceb18cc 78 * Function tests that an empty where hook returns no results.
7884d958 79 */
00be9182 80 public function testContactGetNoResultsHook() {
ff3833b0 81 $this->hookClass->setHook('civicrm_aclWhereClause', [
82 $this,
83 'aclWhereHookNoResults',
84 ]);
85 $result = $this->callAPISuccess('contact', 'get', [
6a488035
TO
86 'check_permissions' => 1,
87 'return' => 'display_name',
ff3833b0 88 ]);
6a488035
TO
89 $this->assertEquals(0, $result['count']);
90 }
91
1028f75e 92 /**
1a4651ba 93 * Function tests that an empty where hook returns exactly 1 result with "view my contact".
1028f75e 94 *
95 * CRM-16512 caused contacts with Edit my contact to be able to view all records.
96 */
1a4651ba 97 public function testContactGetOneResultHookWithViewMyContact() {
1028f75e 98 $this->createLoggedInUser();
ff3833b0 99 $this->hookClass->setHook('civicrm_aclWhereClause', [
100 $this,
101 'aclWhereHookNoResults',
102 ]);
103 CRM_Core_Config::singleton()->userPermissionClass->permissions = [
104 'access CiviCRM',
105 'view my contact',
106 ];
107 $result = $this->callAPISuccess('contact', 'get', [
1028f75e 108 'check_permissions' => 1,
109 'return' => 'display_name',
ff3833b0 110 ]);
1a4651ba
CW
111 $this->assertEquals(1, $result['count']);
112 }
113
114 /**
115 * Function tests that a user with "edit my contact" can edit themselves.
116 */
117 public function testContactEditHookWithEditMyContact() {
1a4651ba 118 $cid = $this->createLoggedInUser();
ff3833b0 119 $this->hookClass->setHook('civicrm_aclWhereClause', [
120 $this,
121 'aclWhereHookNoResults',
122 ]);
123 CRM_Core_Config::singleton()->userPermissionClass->permissions = [
124 'access CiviCRM',
125 'edit my contact',
126 ];
127 $this->callAPISuccess('contact', 'create', [
1a4651ba
CW
128 'check_permissions' => 1,
129 'id' => $cid,
ff3833b0 130 ]);
1028f75e 131 }
132
52ed95a8 133 /**
134 * Ensure contact permissions do not block contact-less location entities.
135 */
136 public function testAddressWithoutContactIDAccess() {
137 $ownID = $this->createLoggedInUser();
ff3833b0 138 CRM_Core_Config::singleton()->userPermissionClass->permissions = [
139 'access CiviCRM',
140 'view all contacts',
141 ];
142 $this->callAPISuccess('Address', 'create', [
52ed95a8 143 'city' => 'Mouseville',
144 'location_type_id' => 'Main',
145 'api.LocBlock.create' => 1,
146 'contact_id' => $ownID,
ff3833b0 147 ]);
148 $this->callAPISuccessGetSingle('Address', [
149 'city' => 'Mouseville',
150 'check_permissions' => 1,
151 ]);
152 CRM_Core_DAO::executeQuery('UPDATE civicrm_address SET contact_id = NULL WHERE contact_id = %1', [
153 1 => [
154 $ownID,
155 'Integer',
156 ],
157 ]);
158 $this->callAPISuccessGetSingle('Address', [
159 'city' => 'Mouseville',
160 'check_permissions' => 1,
161 ]);
52ed95a8 162 }
163
c16ed19b
CW
164 /**
165 * Ensure contact permissions extend to related entities like email
166 */
167 public function testRelatedEntityPermissions() {
0a61b6e2 168 $this->createLoggedInUser();
ff3833b0 169 $disallowedContact = $this->individualCreate([], 0);
170 $this->allowedContactId = $this->individualCreate([], 1);
171 $this->hookClass->setHook('civicrm_aclWhereClause', [
172 $this,
173 'aclWhereOnlyOne',
174 ]);
175 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM'];
176 $testEntities = [
177 'Email' => ['email' => 'null@nothing', 'location_type_id' => 1],
178 'Phone' => ['phone' => '123456', 'location_type_id' => 1],
179 'IM' => ['name' => 'hello', 'location_type_id' => 1],
180 'Website' => ['url' => 'http://test'],
181 'Address' => [
182 'street_address' => '123 Sesame St.',
183 'location_type_id' => 1,
184 ],
185 ];
c16ed19b 186 foreach ($testEntities as $entity => $params) {
ff3833b0 187 $params += [
c16ed19b
CW
188 'contact_id' => $disallowedContact,
189 'check_permissions' => 1,
ff3833b0 190 ];
c16ed19b
CW
191 // We should be prevented from getting or creating entities for a contact we don't have permission for
192 $this->callAPIFailure($entity, 'create', $params);
ff3833b0 193 $this->callAPISuccess($entity, 'create', ['check_permissions' => 0] + $params);
194 $results = $this->callAPISuccess($entity, 'get', [
195 'contact_id' => $disallowedContact,
196 'check_permissions' => 1,
197 ]);
c16ed19b
CW
198 $this->assertEquals(0, $results['count']);
199
200 // We should be allowed to create and get for contacts we do have permission on
201 $params['contact_id'] = $this->allowedContactId;
202 $this->callAPISuccess($entity, 'create', $params);
ff3833b0 203 $results = $this->callAPISuccess($entity, 'get', [
204 'contact_id' => $this->allowedContactId,
205 'check_permissions' => 1,
206 ]);
c16ed19b
CW
207 $this->assertGreaterThan(0, $results['count']);
208 }
ff3833b0 209 $newTag = civicrm_api3('Tag', 'create', [
c6835264 210 'name' => 'Foo123',
ff3833b0 211 ]);
212 $relatedEntities = [
213 'Note' => ['note' => 'abc'],
214 'EntityTag' => ['tag_id' => $newTag['id']],
215 ];
c6835264 216 foreach ($relatedEntities as $entity => $params) {
ff3833b0 217 $params += [
c6835264
CW
218 'entity_id' => $disallowedContact,
219 'entity_table' => 'civicrm_contact',
220 'check_permissions' => 1,
ff3833b0 221 ];
c6835264
CW
222 // We should be prevented from getting or creating entities for a contact we don't have permission for
223 $this->callAPIFailure($entity, 'create', $params);
ff3833b0 224 $this->callAPISuccess($entity, 'create', ['check_permissions' => 0] + $params);
225 $results = $this->callAPISuccess($entity, 'get', [
226 'entity_id' => $disallowedContact,
227 'entity_table' => 'civicrm_contact',
228 'check_permissions' => 1,
229 ]);
c6835264
CW
230 $this->assertEquals(0, $results['count']);
231
232 // We should be allowed to create and get for entities we do have permission on
233 $params['entity_id'] = $this->allowedContactId;
234 $this->callAPISuccess($entity, 'create', $params);
ff3833b0 235 $results = $this->callAPISuccess($entity, 'get', [
236 'entity_id' => $this->allowedContactId,
237 'entity_table' => 'civicrm_contact',
238 'check_permissions' => 1,
239 ]);
c6835264
CW
240 $this->assertGreaterThan(0, $results['count']);
241 }
c16ed19b
CW
242 }
243
6a488035 244 /**
eceb18cc 245 * Function tests all results are returned.
7884d958 246 */
00be9182 247 public function testContactGetAllResultsHook() {
ff3833b0 248 $this->hookClass->setHook('civicrm_aclWhereClause', [
249 $this,
250 'aclWhereHookAllResults',
251 ]);
252 $result = $this->callAPISuccess('contact', 'get', [
7884d958 253 'check_permissions' => 1,
254 'return' => 'display_name',
ff3833b0 255 ]);
6a488035 256
6a488035
TO
257 $this->assertEquals(2, $result['count']);
258 }
7884d958 259
6a488035 260 /**
eceb18cc 261 * Function tests that deleted contacts are not returned.
7884d958 262 */
00be9182 263 public function testContactGetPermissionHookNoDeleted() {
ff3833b0 264 $this->callAPISuccess('contact', 'create', ['id' => 2, 'is_deleted' => 1]);
265 $this->hookClass->setHook('civicrm_aclWhereClause', [
266 $this,
267 'aclWhereHookAllResults',
268 ]);
269 $result = $this->callAPISuccess('contact', 'get', [
7884d958 270 'check_permissions' => 1,
271 'return' => 'display_name',
ff3833b0 272 ]);
6a488035
TO
273 $this->assertEquals(1, $result['count']);
274 }
275
276 /**
eceb18cc 277 * Test permissions limited by hook.
6a488035 278 */
00be9182 279 public function testContactGetHookLimitingHook() {
ff3833b0 280 $this->hookClass->setHook('civicrm_aclWhereClause', [
281 $this,
282 'aclWhereOnlySecond',
283 ]);
6a488035 284
ff3833b0 285 $result = $this->callAPISuccess('contact', 'get', [
6a488035
TO
286 'check_permissions' => 1,
287 'return' => 'display_name',
ff3833b0 288 ]);
6a488035
TO
289 $this->assertEquals(1, $result['count']);
290 }
291
7884d958 292 /**
1028f75e 293 * Confirm that without check permissions we still get 2 contacts returned.
7884d958 294 */
00be9182 295 public function testContactGetHookLimitingHookDontCheck() {
ff3833b0 296 $result = $this->callAPISuccess('contact', 'get', [
4e420887 297 'check_permissions' => 0,
298 'return' => 'display_name',
ff3833b0 299 ]);
6a488035
TO
300 $this->assertEquals(2, $result['count']);
301 }
7884d958 302
6a488035 303 /**
eceb18cc 304 * Check that id works as a filter.
6a488035 305 */
00be9182 306 public function testContactGetIDFilter() {
ff3833b0 307 $this->hookClass->setHook('civicrm_aclWhereClause', [
308 $this,
309 'aclWhereHookAllResults',
310 ]);
311 $result = $this->callAPISuccess('contact', 'get', [
6a488035
TO
312 'sequential' => 1,
313 'id' => 2,
314 'check_permissions' => 1,
ff3833b0 315 ]);
6a488035 316
6a488035
TO
317 $this->assertEquals(1, $result['count']);
318 $this->assertEquals(2, $result['id']);
319 }
320
7884d958 321 /**
eceb18cc 322 * Check that address IS returned.
7884d958 323 */
00be9182 324 public function testContactGetAddressReturned() {
ff3833b0 325 $this->hookClass->setHook('civicrm_aclWhereClause', [
326 $this,
327 'aclWhereOnlySecond',
328 ]);
329 $fullresult = $this->callAPISuccess('contact', 'get', [
7884d958 330 'sequential' => 1,
ff3833b0 331 ]);
7884d958 332 //return doesn't work for all keys - can't fix that here so let's skip ...
333 //prefix & suffix are inconsistent due to CRM-7929
334 // unsure about others but return doesn't work on them
ff3833b0 335 $elementsReturnDoesntSupport = [
7884d958 336 'prefix',
7884d958 337 'suffix',
7884d958 338 'gender',
339 'current_employer',
340 'phone_id',
341 'phone_type_id',
342 'phone',
343 'worldregion_id',
21dfd5f5 344 'world_region',
ff3833b0 345 ];
7884d958 346 $expectedReturnElements = array_diff(array_keys($fullresult['values'][0]), $elementsReturnDoesntSupport);
ff3833b0 347 $result = $this->callAPISuccess('contact', 'get', [
7884d958 348 'check_permissions' => 1,
349 'return' => $expectedReturnElements,
350 'sequential' => 1,
ff3833b0 351 ]);
7884d958 352 $this->assertEquals(1, $result['count']);
353 foreach ($expectedReturnElements as $element) {
354 $this->assertArrayHasKey($element, $result['values'][0]);
6a488035 355 }
7884d958 356 }
357
358 /**
eceb18cc 359 * Check that pledge IS not returned.
7884d958 360 */
00be9182 361 public function testContactGetPledgeIDNotReturned() {
ff3833b0 362 $this->hookClass->setHook('civicrm_aclWhereClause', [
363 $this,
364 'aclWhereHookAllResults',
365 ]);
366 $this->callAPISuccess('contact', 'get', [
7884d958 367 'sequential' => 1,
ff3833b0 368 ]);
369 $result = $this->callAPISuccess('contact', 'get', [
7884d958 370 'check_permissions' => 1,
371 'return' => 'pledge_id',
372 'sequential' => 1,
ff3833b0 373 ]);
7884d958 374 $this->assertArrayNotHasKey('pledge_id', $result['values'][0]);
375 }
6a488035 376
7884d958 377 /**
eceb18cc 378 * Check that pledge IS not an allowable filter.
7884d958 379 */
00be9182 380 public function testContactGetPledgeIDNotFiltered() {
ff3833b0 381 $this->hookClass->setHook('civicrm_aclWhereClause', [
382 $this,
383 'aclWhereHookAllResults',
384 ]);
385 $this->callAPISuccess('contact', 'get', [
7884d958 386 'sequential' => 1,
ff3833b0 387 ]);
388 $result = $this->callAPISuccess('contact', 'get', [
7884d958 389 'check_permissions' => 1,
390 'pledge_id' => 1,
391 'sequential' => 1,
ff3833b0 392 ]);
7884d958 393 $this->assertEquals(2, $result['count']);
394 }
395
396 /**
397 * Check that chaining doesn't bypass permissions
398 */
00be9182 399 public function testContactGetPledgeNotChainable() {
ff3833b0 400 $this->hookClass->setHook('civicrm_aclWhereClause', [
401 $this,
402 'aclWhereOnlySecond',
403 ]);
404 $this->callAPISuccess('contact', 'get', [
7884d958 405 'sequential' => 1,
ff3833b0 406 ]);
407 $this->callAPIFailure('contact', 'get', [
408 'check_permissions' => 1,
409 'api.pledge.get' => 1,
410 'sequential' => 1,
411 ],
d235daf6 412 'Error in call to Pledge_get : API permission check failed for Pledge/get call; insufficient permission: require access CiviCRM and access CiviPledge'
7884d958 413 );
414 }
6a488035 415
00be9182 416 public function setupCoreACL() {
ae4bb4c9 417 $this->createLoggedInUser();
ff3833b0 418 $this->_permissionedDisabledGroup = $this->groupCreate([
92915c55
TO
419 'title' => 'pick-me-disabled',
420 'is_active' => 0,
421 'name' => 'pick-me-disabled',
ff3833b0 422 ]);
423 $this->_permissionedGroup = $this->groupCreate([
92915c55
TO
424 'title' => 'pick-me-active',
425 'is_active' => 1,
426 'name' => 'pick-me-active',
ff3833b0 427 ]);
ae4bb4c9
EM
428 $this->setupACL();
429 }
5896d037 430
ae4bb4c9
EM
431 /**
432 * @dataProvider entities
433 * confirm that without check permissions we still get 2 contacts returned
1e1fdcf6 434 * @param $entity
ae4bb4c9 435 */
00be9182 436 public function testEntitiesGetHookLimitingHookNoCheck($entity) {
ff3833b0 437 CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
ae4bb4c9 438 $this->setUpEntities($entity);
ff3833b0 439 $this->hookClass->setHook('civicrm_aclWhereClause', [
440 $this,
441 'aclWhereHookNoResults',
442 ]);
443 $result = $this->callAPISuccess($entity, 'get', [
ae4bb4c9
EM
444 'check_permissions' => 0,
445 'return' => 'contact_id',
ff3833b0 446 ]);
ae4bb4c9
EM
447 $this->assertEquals(2, $result['count']);
448 }
449
450 /**
451 * @dataProvider entities
452 * confirm that without check permissions we still get 2 entities returned
1e1fdcf6 453 * @param $entity
ae4bb4c9 454 */
00be9182 455 public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) {
ae4bb4c9
EM
456 $this->setupCoreACL();
457 //CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
458 $this->setUpEntities($entity);
ff3833b0 459 $this->hookClass->setHook('civicrm_aclWhereClause', [
460 $this,
461 'aclWhereHookNoResults',
462 ]);
463 $result = $this->callAPISuccess($entity, 'get', [
ae4bb4c9
EM
464 'check_permissions' => 0,
465 'return' => 'contact_id',
ff3833b0 466 ]);
ae4bb4c9
EM
467 $this->assertEquals(2, $result['count']);
468 }
5896d037 469
ae4bb4c9
EM
470 /**
471 * @dataProvider entities
472 * confirm that with check permissions we don't get entities
1e1fdcf6
EM
473 * @param $entity
474 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 475 */
00be9182 476 public function testEntitiesGetCoreACLLimitingCheck($entity) {
ae4bb4c9
EM
477 $this->setupCoreACL();
478 $this->setUpEntities($entity);
ff3833b0 479 $result = $this->callAPISuccess($entity, 'get', [
ae4bb4c9
EM
480 'check_permissions' => 1,
481 'return' => 'contact_id',
ff3833b0 482 ]);
ae4bb4c9
EM
483 $this->assertEquals(0, $result['count']);
484 }
485
ae4bb4c9
EM
486 /**
487 * @dataProvider entities
488 * Function tests that an empty where hook returns no results
1028f75e 489 * @param string $entity
1e1fdcf6 490 * @throws \PHPUnit_Framework_IncompleteTestError
ae4bb4c9 491 */
00be9182 492 public function testEntityGetNoResultsHook($entity) {
ae4bb4c9 493 $this->markTestIncomplete('hook acls only work with contacts so far');
ff3833b0 494 CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
ae4bb4c9 495 $this->setUpEntities($entity);
ff3833b0 496 $this->hookClass->setHook('civicrm_aclWhereClause', [
497 $this,
498 'aclWhereHookNoResults',
499 ]);
500 $result = $this->callAPISuccess($entity, 'get', [
ae4bb4c9 501 'check_permission' => 1,
ff3833b0 502 ]);
ae4bb4c9
EM
503 $this->assertEquals(0, $result['count']);
504 }
505
506 /**
507 * @return array
508 */
509 public static function entities() {
ff3833b0 510 return [
511 ['contribution'],
512 ['participant'],
513 ];// @todo array('pledge' => 'pledge')
ae4bb4c9
EM
514 }
515
516 /**
517 * Create 2 entities
1e1fdcf6 518 * @param $entity
ae4bb4c9
EM
519 */
520 public function setUpEntities($entity) {
521 $baoObj = new CRM_Core_DAO();
ff3833b0 522 $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), [], 2, 0);
523 CRM_Core_Config::singleton()->userPermissionClass->permissions = [
ae4bb4c9
EM
524 'access CiviCRM',
525 'access CiviContribute',
526 'access CiviEvent',
527 'view event participants',
ff3833b0 528 ];
ae4bb4c9
EM
529 }
530
bbd2743b 531 /**
532 * Basic check that an unpermissioned call keeps working and permissioned call fails.
533 */
534 public function testGetActivityNoPermissions() {
ff3833b0 535 $this->setPermissions([]);
536 $this->callAPISuccess('Activity', 'get', []);
537 $this->callAPIFailure('Activity', 'get', ['check_permissions' => 1]);
bbd2743b 538 }
539
540 /**
541 * View all activities is enough regardless of contact ACLs.
542 */
cdacd6ab 543 public function testGetActivityViewAllActivitiesDoesntCutItAnymore() {
bbd2743b 544 $activity = $this->activityCreate();
ff3833b0 545 $this->setPermissions(['view all activities', 'access CiviCRM']);
546 $this->callAPISuccessGetCount('Activity', [
547 'check_permissions' => 1,
548 'id' => $activity['id'],
549 ], 0);
bbd2743b 550 }
551
552 /**
553 * View all activities is required unless id is passed in.
554 */
cdacd6ab 555 public function testGetActivityViewAllContactsEnoughWithoutID() {
ff3833b0 556 $this->setPermissions(['view all contacts', 'access CiviCRM']);
557 $this->callAPISuccess('Activity', 'get', ['check_permissions' => 1]);
bbd2743b 558 }
559
560 /**
3af8de9f 561 * Without view all activities contact level acls are used.
bbd2743b 562 */
563 public function testGetActivityViewAllContactsEnoughWIthID() {
564 $activity = $this->activityCreate();
ff3833b0 565 $this->setPermissions(['view all contacts', 'access CiviCRM']);
566 $this->callAPISuccess('Activity', 'getsingle', [
567 'check_permissions' => 1,
568 'id' => $activity['id'],
569 ]);
bbd2743b 570 }
571
572 /**
573 * View all activities is required unless id is passed in, in which case ACLs are used.
574 */
575 public function testGetActivityAccessCiviCRMNotEnough() {
576 $activity = $this->activityCreate();
ff3833b0 577 $this->setPermissions(['access CiviCRM']);
578 $this->callAPIFailure('Activity', 'getsingle', [
579 'check_permissions' => 1,
580 'id' => $activity['id'],
581 ]);
bbd2743b 582 }
583
3af8de9f 584 /**
585 * Check that component related activity filtering.
586 *
587 * If the contact does NOT have permission to 'view all contacts' but they DO have permission
588 * to view the contact in question they will only see the activities of components they have access too.
589 *
590 * (logically the same component limit should apply when they have access to view all too but....
591 * adding test for 'how it is at the moment.)
592 */
593 public function testGetActivityCheckPermissionsByComponent() {
594 $activity = $this->activityCreate(['activity_type_id' => 'Contribution']);
595 $activity2 = $this->activityCreate(['activity_type_id' => 'Pledge Reminder']);
ff3833b0 596 $this->hookClass->setHook('civicrm_aclWhereClause', [
597 $this,
598 'aclWhereHookAllResults',
599 ]);
3af8de9f 600 $this->setPermissions(['access CiviCRM', 'access CiviContribute']);
ff3833b0 601 $this->callAPISuccessGetSingle('Activity', [
602 'check_permissions' => 1,
603 'id' => ['IN' => [$activity['id'], $activity2['id']]],
604 ]);
605 $this->callAPISuccessGetCount('Activity', [
606 'check_permissions' => 1,
607 'id' => ['IN' => [$activity['id'], $activity2['id']]],
608 ], 1);
ff2a3553 609
3af8de9f 610 }
611
c4937fe9 612 /**
613 * Check that component related activity filtering works for CiviCase.
614 */
615 public function testGetActivityCheckPermissionsByCaseComponent() {
616 CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
617 $activity = $this->activityCreate(['activity_type_id' => 'Open Case']);
618 $activity2 = $this->activityCreate(['activity_type_id' => 'Pledge Reminder']);
ff3833b0 619 $this->hookClass->setHook('civicrm_aclWhereClause', [
620 $this,
621 'aclWhereHookAllResults',
622 ]);
623 $this->setPermissions([
624 'access CiviCRM',
625 'access CiviContribute',
626 'access all cases and activities',
627 ]);
628 $this->callAPISuccessGetSingle('Activity', [
629 'check_permissions' => 1,
630 'id' => ['IN' => [$activity['id'], $activity2['id']]],
631 ]);
632 $this->callAPISuccessGetCount('Activity', [
633 'check_permissions' => 1,
634 'id' => ['IN' => [$activity['id'], $activity2['id']]],
635 ], 1);
c4937fe9 636 }
637
bbd2743b 638 /**
639 * Check that activities can be retrieved by ACL.
640 *
641 * The activities api applies ACLs in a very limited circumstance, if id is passed in.
642 * Otherwise it sticks with the blunt original permissions.
643 */
644 public function testGetActivityByACL() {
ff3833b0 645 $this->setPermissions(['access CiviCRM']);
bbd2743b 646 $activity = $this->activityCreate();
647
ff3833b0 648 $this->hookClass->setHook('civicrm_aclWhereClause', [
649 $this,
650 'aclWhereHookAllResults',
651 ]);
652 $this->callAPISuccessGetSingle('Activity', [
653 'check_permissions' => 1,
654 'id' => $activity['id'],
655 ]);
656 $this->callAPISuccessGetCount('Activity', [
657 'check_permissions' => 1,
658 'id' => $activity['id'],
659 ]);
bbd2743b 660 }
661
662 /**
cdacd6ab 663 * To leverage ACL permission to view an activity you must be able to see any of the contacts.
bbd2743b 664 */
665 public function testGetActivityByAclCannotViewAllContacts() {
cdacd6ab 666 $activity = $this->activityCreate(['assignee_contact_id' => $this->individualCreate()]);
667 $contacts = $this->getActivityContacts($activity);
668 $this->setPermissions(['access CiviCRM']);
669
670 foreach ($contacts as $role => $contact_id) {
671 $this->allowedContactId = $contact_id;
ff3833b0 672 $this->hookClass->setHook('civicrm_aclWhereClause', [
673 $this,
674 'aclWhereOnlyOne',
675 ]);
cdacd6ab 676 $this->cleanupCachedPermissions();
677 $result = $this->callAPISuccessGetSingle('Activity', [
678 'check_permissions' => 1,
679 'id' => $activity['id'],
ff3833b0 680 'return' => [
681 'source_contact_id',
682 'target_contact_id',
683 'assignee_contact_id',
684 ],
cdacd6ab 685 ]);
ff3833b0 686 foreach ([
687 'source_contact',
688 'target_contact',
689 'assignee_contact',
690 ] as $roleName) {
cdacd6ab 691 $roleKey = $roleName . '_id';
692 if ($role !== $roleKey) {
693 $this->assertTrue(empty($result[$roleKey]), "Only contact in $role is permissioned to be returned, not $roleKey");
694 }
695 else {
696 $this->assertEquals([$contact_id], (array) $result[$roleKey]);
697 $this->assertTrue(!empty($result[$roleName . '_name']));
698 }
699 }
700 }
701 }
702
703 /**
704 * To leverage ACL permission to view an activity you must be able to see any of the contacts.
705 */
706 public function testGetActivityByAclCannotViewAnyContacts() {
bbd2743b 707 $activity = $this->activityCreate();
708 $contacts = $this->getActivityContacts($activity);
ff3833b0 709 $this->setPermissions(['access CiviCRM']);
bbd2743b 710
711 foreach ($contacts as $contact_id) {
ff3833b0 712 $this->callAPIFailure('Activity', 'getsingle', [
713 'check_permissions' => 1,
714 'id' => $activity['id'],
715 ]);
bbd2743b 716 }
717 }
718
719 /**
720 * Check that if the source contact is deleted but we can view the others we can see the activity.
721 *
722 * CRM-18409.
723 *
724 * @throws \CRM_Core_Exception
725 */
726 public function testGetActivityACLSourceContactDeleted() {
ff3833b0 727 $this->setPermissions(['access CiviCRM', 'delete contacts']);
bbd2743b 728 $activity = $this->activityCreate();
729 $contacts = $this->getActivityContacts($activity);
730
ff3833b0 731 $this->hookClass->setHook('civicrm_aclWhereClause', [
732 $this,
733 'aclWhereHookAllResults',
734 ]);
bbd2743b 735 $this->contactDelete($contacts['source_contact_id']);
ff3833b0 736 $this->callAPISuccess('Activity', 'getsingle', [
737 'check_permissions' => 1,
738 'id' => $activity['id'],
739 ]);
bbd2743b 740 }
741
f404486e
SL
742 /**
743 * Test get activities multiple ids with check permissions
744 * CRM-20441
745 */
746 public function testActivitiesGetMultipleIdsCheckPermissions() {
747 $this->createLoggedInUser();
748 $activity = $this->activityCreate();
749 $activity2 = $this->activityCreate();
ff3833b0 750 $this->setPermissions(['access CiviCRM']);
751 $this->hookClass->setHook('civicrm_aclWhereClause', [
752 $this,
753 'aclWhereHookAllResults',
754 ]);
f404486e 755 // Get activities associated with contact $this->_contactID.
ff3833b0 756 $params = [
757 'id' => ['IN' => [$activity['id'], $activity2['id']]],
f404486e 758 'check_permissions' => TRUE,
ff3833b0 759 ];
f404486e
SL
760 $result = $this->callAPISuccess('activity', 'get', $params);
761 $this->assertEquals(2, $result['count']);
762 }
763
764 /**
765 * Test get activities multiple ids with check permissions
766 * Limit access to One contact
767 * CRM-20441
768 */
769 public function testActivitiesGetMultipleIdsCheckPermissionsLimitedACL() {
770 $this->createLoggedInUser();
771 $activity = $this->activityCreate();
772 $contacts = $this->getActivityContacts($activity);
ff3833b0 773 $this->setPermissions(['access CiviCRM']);
f404486e
SL
774 foreach ($contacts as $contact_id) {
775 $this->allowedContacts[] = $contact_id;
776 }
ff3833b0 777 $this->hookClass->setHook('civicrm_aclWhereClause', [
778 $this,
779 'aclWhereMultipleContacts',
780 ]);
f404486e 781 $contact2 = $this->individualCreate();
ff3833b0 782 $activity2 = $this->activityCreate(['source_contact_id' => $contact2]);
f404486e 783 // Get activities associated with contact $this->_contactID.
ff3833b0 784 $params = [
785 'id' => ['IN' => [$activity['id']]],
f404486e 786 'check_permissions' => TRUE,
ff3833b0 787 ];
f404486e
SL
788 $result = $this->callAPISuccess('activity', 'get', $params);
789 $this->assertEquals(1, $result['count']);
ff3833b0 790 $this->callAPIFailure('activity', 'get', array_merge($params, [
791 'id' => [
792 'IN',
793 [$activity2['id']],
794 ],
795 ]));
f404486e
SL
796 }
797
dfe0e2e1
SL
798 /**
799 * Test get activities multiple ids with check permissions
800 * CRM-20441
801 */
802 public function testActivitiesGetMultipleIdsCheckPermissionsNotIN() {
803 $this->createLoggedInUser();
804 $activity = $this->activityCreate();
805 $activity2 = $this->activityCreate();
ff3833b0 806 $this->setPermissions(['access CiviCRM']);
807 $this->hookClass->setHook('civicrm_aclWhereClause', [
808 $this,
809 'aclWhereHookAllResults',
810 ]);
dfe0e2e1 811 // Get activities associated with contact $this->_contactID.
ff3833b0 812 $params = [
813 'id' => ['NOT IN' => [$activity['id'], $activity2['id']]],
dfe0e2e1 814 'check_permissions' => TRUE,
ff3833b0 815 ];
3c9d67b0 816 $result = $this->callAPISuccess('activity', 'get', $params);
817 $this->assertEquals(0, $result['count']);
dfe0e2e1
SL
818 }
819
bbd2743b 820 /**
821 * Get the contacts for the activity.
822 *
823 * @param $activity
824 *
825 * @return array
826 * @throws \CRM_Core_Exception
827 */
828 protected function getActivityContacts($activity) {
ff3833b0 829 $contacts = [];
bbd2743b 830
ff3833b0 831 $activityContacts = $this->callAPISuccess('ActivityContact', 'get', [
bbd2743b 832 'activity_id' => $activity['id'],
ff3833b0 833 ]
bbd2743b 834 );
835
ff3833b0 836 $activityRecordTypes = $this->callAPISuccess('ActivityContact', 'getoptions', ['field' => 'record_type_id']);
bbd2743b 837 foreach ($activityContacts['values'] as $activityContact) {
838 $type = $activityRecordTypes['values'][$activityContact['record_type_id']];
839 switch ($type) {
840 case 'Activity Source':
841 $contacts['source_contact_id'] = $activityContact['contact_id'];
842 break;
843
844 case 'Activity Targets':
845 $contacts['target_contact_id'] = $activityContact['contact_id'];
846 break;
847
848 case 'Activity Assignees':
849 $contacts['assignee_contact_id'] = $activityContact['contact_id'];
850 break;
851
852 }
853 }
854 return $contacts;
855 }
856
8e12938a 857 /**
858 * Test that the 'everyone' group can be given access to a contact.
859 */
860 public function testGetACLEveryonePermittedEntity() {
861 $this->setupScenarioCoreACLEveryonePermittedToGroup();
1bcdee33 862 $this->callAPISuccessGetCount('Contact', [
8e12938a 863 'id' => $this->scenarioIDs['Contact']['permitted_contact'],
864 'check_permissions' => 1,
1bcdee33 865 ], 1);
866
867 $this->callAPISuccessGetCount('Contact', [
868 'id' => $this->scenarioIDs['Contact']['non_permitted_contact'],
869 'check_permissions' => 1,
870 ], 0);
1876e376 871
872 // Also check that we can access ACLs through a path that uses the acl_contact_cache table.
873 // historically this has caused errors due to the key_constraint on that table.
874 // This is a bit of an artificial check as we have to amp up permissions to access this api.
875 // However, the lower level function is more directly accessed through the Contribution & Event & Profile
876 $dupes = $this->callAPISuccess('Contact', 'duplicatecheck', [
877 'match' => [
878 'first_name' => 'Anthony',
879 'last_name' => 'Anderson',
880 'contact_type' => 'Individual',
881 'email' => 'anthony_anderson@civicrm.org',
882 ],
883 'check_permissions' => 0,
884 ]);
a99b82c5 885 $this->assertEquals(2, $dupes['count']);
678bd58a 886 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM'];
1876e376 887
888 $dupes = $this->callAPISuccess('Contact', 'duplicatecheck', [
889 'match' => [
890 'first_name' => 'Anthony',
891 'last_name' => 'Anderson',
892 'contact_type' => 'Individual',
893 'email' => 'anthony_anderson@civicrm.org',
894 ],
895 'check_permissions' => 1,
896 ]);
897 $this->assertEquals(1, $dupes['count']);
898
8e12938a 899 }
900
6a488035 901}