Commit | Line | Data |
---|---|---|
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 | 20 | namespace api\v4\Custom; |
317103ab CW |
21 | |
22 | use Civi\Api4\ACL; | |
23 | use Civi\Api4\Contact; | |
24 | use Civi\Api4\CustomField; | |
25 | use Civi\Api4\CustomGroup; | |
26 | use Civi\Api4\CustomValue; | |
27 | ||
28 | /** | |
29 | * @group headless | |
30 | */ | |
46f571dd | 31 | class 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 | } |