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