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