APIv4 - Reorganize test classes, don't use transactions for custom value tests
[civicrm-core.git] / tests / phpunit / api / v4 / Custom / CustomGroupACLTest.php
CommitLineData
317103ab
CW
1<?php
2
3/*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
11 */
12
13/**
14 *
15 * @package CRM
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 */
18
19
46f571dd 20namespace api\v4\Custom;
317103ab
CW
21
22use Civi\Api4\ACL;
23use Civi\Api4\Contact;
24use Civi\Api4\CustomField;
25use Civi\Api4\CustomGroup;
26use Civi\Api4\CustomValue;
27
28/**
29 * @group headless
30 */
46f571dd 31class CustomGroupACLTest extends CustomTestBase {
317103ab
CW
32
33 public function tearDown(): void {
34 parent::tearDown();
35 // Delete all ACLs
36 ACL::delete(FALSE)->addWhere('id', '>', 0)->execute();
37 unset(\Civi::$statics['CRM_Contact_BAO_Contact_Permission']);
38 \CRM_Core_DAO::executeQuery('TRUNCATE civicrm_acl_contact_cache');
39 }
40
41 public function testViewEditCustomGroupACLs() {
42 $groups = ['readWrite' => 'Edit', 'readOnly' => 'View', 'superSecret' => NULL];
43 $v3 = [];
44
45 foreach ($groups as $name => $access) {
46 $singleGroup = CustomGroup::create(FALSE)
ed3f5877 47 ->addValue('title', 'My' . ucfirst($name) . 'Single')
317103ab
CW
48 ->addValue('extends', 'Individual')
49 ->addChain('field', CustomField::create()
50 ->addValue('label', 'MyField')
51 ->addValue('html_type', 'Text')
52 ->addValue('custom_group_id', '$id'), 0)
53 ->execute()->single();
54 $v3['single'][$name] = 'custom_' . $singleGroup['field']['id'];
55 $multiGroup = CustomGroup::create(FALSE)
ed3f5877 56 ->addValue('title', 'My' . ucfirst($name) . 'Multi')
317103ab
CW
57 ->addValue('extends', 'Individual')
58 ->addValue('is_multiple', TRUE)
59 ->addChain('field', CustomField::create()
60 ->addValue('label', 'MyField')
61 ->addValue('html_type', 'Text')
62 ->addValue('custom_group_id', '$id'), 0)
63 ->execute()->single();
64 $v3['multi'][$name] = 'custom_' . $multiGroup['field']['id'];
65 if ($access) {
66 ACL::create(FALSE)->setValues([
67 'name' => $name . 'Single',
68 'entity_id' => 0,
69 'operation' => $access,
70 'object_table' => 'civicrm_custom_group',
71 'object_id' => $singleGroup['id'],
72 ])->execute();
73 ACL::create(FALSE)->setValues([
74 'name' => $name . 'Multi',
75 'entity_id' => 0,
76 'operation' => $access,
77 'object_table' => 'civicrm_custom_group',
78 'object_id' => $multiGroup['id'],
79 ])->execute();
80 }
81 }
82
83 $this->createLoggedInUser();
84 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access all custom data', 'access CiviCRM', 'add contacts'];
85
86 $cid = Contact::create()->setValues([
87 'contact_type' => 'Individual',
88 'first_name' => 'test123',
89 'MyReadWriteSingle.MyField' => '123',
90 'MyReadOnlySingle.MyField' => '456',
91 'MySuperSecretSingle.MyField' => '789',
92 ])->execute()->first()['id'];
93
94 // TEST SINGLE-VALUE CUSTOM GROUPS
95
96 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'view all contacts', 'edit all contacts'];
97
98 // Ensure ACLs apply to APIv4 get
99 $result = Contact::get()
100 ->addWhere('id', '=', $cid)
101 ->addSelect('custom.*')
102 ->execute()->single();
103 $this->assertEquals('123', $result['MyReadWriteSingle.MyField']);
104 $this->assertEquals('456', $result['MyReadOnlySingle.MyField']);
105 $this->assertArrayNotHasKey('MySuperSecretSingle.MyField', $result);
106
107 // Ensure ACLs apply to APIv3 get
108 $result = civicrm_api3('Contact', 'get', [
109 'id' => $cid,
110 'check_permissions' => 1,
111 'return' => [$v3['single']['readWrite'], $v3['single']['readOnly'], $v3['single']['superSecret']],
112 ])['values'][$cid];
113 $this->assertEquals('123', $result[$v3['single']['readWrite']]);
114 $this->assertArrayNotHasKey($v3['single']['superSecret'], $result);
115 $this->assertEquals('456', $result[$v3['single']['readOnly']]);
116
117 // Try to update all fields - ACLs will restrict based on write access
118 Contact::update()->setValues([
119 'id' => $cid,
120 'first_name' => 'test1234',
121 'MyReadWriteSingle.MyField' => '1234',
122 'MyReadOnlySingle.MyField' => '4567',
123 'MySuperSecretSingle.MyField' => '7890',
124 ])->execute();
125
126 // Verify only first name & readWrite field were altered by APIv4
127 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access all custom data', 'access CiviCRM', 'view all contacts', 'edit all contacts'];
128 $result = Contact::get()
129 ->addWhere('id', '=', $cid)
130 ->addSelect('first_name', 'custom.*')
131 ->execute()->single();
132 $this->assertEquals('test1234', $result['first_name']);
133 $this->assertEquals('1234', $result['MyReadWriteSingle.MyField']);
134 $this->assertEquals('456', $result['MyReadOnlySingle.MyField']);
135 $this->assertEquals('789', $result['MySuperSecretSingle.MyField']);
136
137 // Try updating all fields with APIv3 - ACLs will restrict based on write access
138 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'view all contacts', 'edit all contacts'];
139 civicrm_api3('Contact', 'create', [
140 'check_permissions' => 1,
141 'id' => $cid,
142 'first_name' => 'test12345',
143 $v3['single']['readWrite'] => '12345',
144 $v3['single']['readOnly'] => '45678',
145 $v3['single']['superSecret'] => '7890!',
146 ]);
147
148 // Verify only first name & readWrite field were altered by APIv3
149 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access all custom data', 'access CiviCRM', 'view all contacts', 'edit all contacts'];
150 $result = Contact::get()
151 ->addWhere('id', '=', $cid)
152 ->addSelect('first_name', 'custom.*')
153 ->execute()->single();
154 $this->assertEquals('test12345', $result['first_name']);
155 $this->assertEquals('12345', $result['MyReadWriteSingle.MyField']);
156 $this->assertEquals('456', $result['MyReadOnlySingle.MyField']);
157 $this->assertEquals('789', $result['MySuperSecretSingle.MyField']);
158
159 // TEST MULTI-VALUE CUSTOM GROUPS
160
161 $multiValues = [
162 'MyReadWriteMulti' => ['red', 'blue'],
163 'MyReadOnlyMulti' => ['purple', 'orange'],
164 'MySuperSecretMulti' => ['brown', 'black'],
165 ];
166 foreach ($multiValues as $groupName => $values) {
167 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access all custom data', 'access CiviCRM', 'view all contacts', 'edit all contacts'];
168 foreach ($values as $value) {
169 CustomValue::create($groupName)
170 ->addValue('MyField', $value)
171 ->addValue('entity_id', $cid)
172 ->execute();
173 }
174 // Check that all but SuperSecret values can be read
175 try {
176 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'view all contacts', 'edit all contacts'];
177 $result = CustomValue::get($groupName)
178 ->addWhere('entity_id', '=', $cid)
179 ->addOrderBy('id')
180 ->execute();
181 if ($groupName === 'MySuperSecretMulti') {
182 $this->fail('API call should have failed');
183 }
184 $this->assertEquals($values, $result->column('MyField'));
185 }
186 catch (\API_Exception $e) {
187 if ($groupName !== 'MySuperSecretMulti') {
188 $this->fail('API get should have succeeded');
189 }
190 }
191 // Check that it works via join also
192 $result = Contact::get()
193 ->addWhere('id', '=', $cid)
194 ->addJoin("Custom_$groupName AS customGroup")
195 ->addSelect("customGroup.MyField")
196 ->execute();
197 if ($groupName !== 'MySuperSecretMulti') {
198 $this->assertEquals($values, $result->column("customGroup.MyField"));
199 }
200 else {
201 foreach ($result as $row) {
202 $this->assertArrayNotHasKey("customGroup.MyField", $row);
203 }
204 }
205 try {
206 CustomValue::create($groupName)
207 ->addValue('MyField', 'new')
208 ->addValue('entity_id', $cid)
209 ->execute();
210 if ($groupName !== 'MyReadWriteMulti') {
211 $this->fail('API call should have failed');
212 }
213 }
214 catch (\API_Exception $e) {
215 if ($groupName === 'MyReadWriteMulti') {
216 $this->fail('API create should have succeeded');
217 }
218 }
219 }
220 // Try updating with APIv3
221 civicrm_api3('Contact', 'create', [
222 'check_permissions' => 1,
223 'id' => $cid,
224 'first_name' => 'test12345',
225 // Should update the first record in the "readWrite" group
226 $v3['multi']['readWrite'] . '_1' => 'changed1',
227 // These 2 updates should fail due to ACLs
228 $v3['multi']['readOnly'] . '_1' => 'changed2',
229 $v3['multi']['superSecret'] . '_1' => 'changed3',
230 ]);
231
232 // Ensure only readWrite group has been modified
233 \CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access all custom data', 'access CiviCRM', 'view all contacts', 'edit all contacts'];
234 $expectedValues = [
235 'MyReadWriteMulti' => ['changed1', 'blue', 'new'],
236 'MyReadOnlyMulti' => ['purple', 'orange'],
237 'MySuperSecretMulti' => ['brown', 'black'],
238 ];
239 foreach ($expectedValues as $groupName => $expected) {
240 $result = CustomValue::get($groupName)
241 ->addWhere('entity_id', '=', $cid)
242 ->addOrderBy('id')
243 ->execute();
244 $this->assertEquals($expected, $result->column('MyField'));
245 }
246
247 }
248
249}