Permissions logic and error handling for view-only Contact Reference Autocomplete-Select field
Overview
I have a custom view-only field with Data Type Contact Reference and Field Type Autocomplete-Select. The field value is populated via custom PHP code.
A user with "access CiviCRM" permission can view this field. But if they try to edit the contact, they get a confusing "QuickForm Error: nonexistent html element" error message unless they also have the "access contact reference fields" permission.
There are several issues to consider:
- Should the error message be clarified by changing it to something like "Permission denied for Contact Reference field"? At a minimum, this would make diagnosing and troubleshooting the problem easier.
- Since the user can already view the field, when entering "edit" mode, should the permission check be skipped so that the field shows up normally (as "view-only") on the "edit" form? It seems to me this is the correct resolution.
- Should the view-only field be dropped from the "edit" form? It seems to me this doesn't make much sense, since the "view" and "edit" forms would then be inconsistent.
- Should the view-only field be dropped from both the "view" and the "edit" forms? This depends on what is intended with the "access contact reference fields" permission. If the intention is to prevent the user from even viewing such fields, then the Contact Reference field should be dropped from both.
The most relevant code is https://lab.civicrm.org/dev/core/-/blob/master/CRM/Core/BAO/CustomField.php#L905 and https://lab.civicrm.org/dev/core/-/blob/master/CRM/Core/BAO/CustomField.php#L984. See additional comments below.
Reproduction steps
- Create a custom Contact Reference field and configure it with Field Type "Autocomplete-Select".
- As a Civi administrator, create a test contact with data in the new custom field.
- Change the settings for the custom field to "view-only".
- As a less privileged Civi user, without the "access contact reference fields" permission, view the test contact. Result: The Contact Reference field is visible.
- As the less privileged user, attempt to edit the contact. Result: "QuickForm Error: nonexistent html element"
Current behaviour
Current behavior is described in the Reproduction steps.
Expected behaviour
As noted in the description, the correct behavior depends on what is intended by the "access contact reference fields" permission. I will assume that the correct interpretation is that users lacking the "access contact reference fields" permission are allowed to view such fields, but are not allowed to edit such fields.
Assuming this is the correct understanding, then when a user tries to edit a contact, the "view-only" Contact Reference field should simply be displayed normally. Please see below for a suggested code fix.
Environment information
- Browser: Chrome 97.0.4692.71
- CiviCRM: 5.45.1
- PHP: 7.3
- CMS: WordPress 5.8.3
- Database: MariaDB 10.4
- Web Server: Apache 2.4
Comments
I believe the following code change would produce the Expected behavior:
Starting at https://lab.civicrm.org/dev/core/-/blob/master/CRM/Core/BAO/CustomField.php#L901, change:
case 'Autocomplete-Select':
static $customUrls = [];
if ($field->data_type == 'ContactReference') {
// break if contact does not have permission to access ContactReference
if (!CRM_Core_Permission::check('access contact reference fields')) {
break;
}
to:
case 'Autocomplete-Select':
static $customUrls = [];
if ($field->data_type == 'ContactReference') {
// break if contact does not have permission to access ContactReference
if (!$field->is_view && !$search && !CRM_Core_Permission::check('access contact reference fields')) {
break;
}
Line # 905 is changed. The !$field->is_view && !$search
condition is copied from https://lab.civicrm.org/dev/core/-/blob/master/CRM/Core/BAO/CustomField.php#L984.
With this change, the "view-only" field will become "frozen" (view-only) on the "edit" form.