From: Coleman Watts Date: Fri, 5 Aug 2022 18:10:51 +0000 (-0400) Subject: Afform - configure existing entity widget X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=19ff504ec760298c377db0e61287017454213280;p=civicrm-core.git Afform - configure existing entity widget --- diff --git a/Civi/Api4/Generic/AutocompleteAction.php b/Civi/Api4/Generic/AutocompleteAction.php index 700310ad6a..0e406cfc75 100644 --- a/Civi/Api4/Generic/AutocompleteAction.php +++ b/Civi/Api4/Generic/AutocompleteAction.php @@ -182,6 +182,21 @@ class AutocompleteAction extends AbstractAction { ) { return TRUE; } + // Proceed only if permissions are being enforced.' + // Anonymous users in permission-bypass mode should not be allowed to set arbitrary filters. + if ($this->getCheckPermissions()) { + $field = $this->getField($fieldName); + try { + civicrm_api4($field['entity'], 'getFields', [ + 'action' => 'get', + 'where' => [['name', '=', $fieldName]], + ])->single(); + return TRUE; + } + catch (\CRM_Core_Exception $e) { + return FALSE; + } + } return FALSE; } diff --git a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php index 45e6f0c237..0cd0f230a1 100644 --- a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php +++ b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php @@ -56,7 +56,7 @@ trait SavedSearchInspectorTrait { } if (is_array($this->savedSearch)) { $this->savedSearch += ['api_params' => []]; - $this->savedSearch['api_params'] += ['select' => [], 'where' => []]; + $this->savedSearch['api_params'] += ['version' => 4, 'select' => [], 'where' => []]; } $this->_apiParams = ($this->savedSearch['api_params'] ?? []) + ['select' => [], 'where' => []]; } diff --git a/ang/crmUi.js b/ang/crmUi.js index 1e59ef0dbd..33588accbd 100644 --- a/ang/crmUi.js +++ b/ang/crmUi.js @@ -704,6 +704,32 @@ }; }) + // Render a crmAutocomplete APIv4 widget + // usage: + .directive('crmAutocomplete', function () { + return { + require: { + ngModel: '?ngModel' + }, + bindToController: { + crmAutocomplete: '<', + crmAutocompleteParams: '<' + }, + controller: function($element, $timeout) { + var ctrl = this; + $timeout(function() { + $element.crmAutocomplete(ctrl.crmAutocomplete, ctrl.crmAutocompleteParams); + // Ensure widget is updated when model changes + if (ctrl.ngModel) { + ctrl.ngModel.$render = function() { + $element.val(ctrl.ngModel.$viewValue || '').change(); + }; + } + }); + } + }; + }) + // validate multiple email text // usage: .directive('crmMultipleEmail', function ($parse, $timeout) { diff --git a/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php b/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php index 566a5d387c..469b97dd92 100644 --- a/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php +++ b/ext/afform/admin/Civi/AfformAdmin/AfformAdminMeta.php @@ -127,7 +127,7 @@ class AfformAdminMeta { // Add existing entity field $idField = CoreUtil::getIdFieldName($entityName); $fields[$idField]['readonly'] = FALSE; - $fields[$idField]['input_type'] = 'EntityRef'; + $fields[$idField]['input_type'] = 'Existing'; $fields[$idField]['is_id'] = TRUE; $fields[$idField]['label'] = E::ts('Existing %1', [1 => CoreUtil::getInfoItem($entityName, 'title')]); // Mix in alterations declared by afform entities diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiField-menu.html b/ext/afform/admin/ang/afGuiEditor/elements/afGuiField-menu.html index 85de8d309f..fa12d3f843 100644 --- a/ext/afform/admin/ang/afGuiEditor/elements/afGuiField-menu.html +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiField-menu.html @@ -1,4 +1,4 @@ -
  • +
  • +
  • +
    + + +
    +
  • {{:: ts('Required') }}
  • -
  • +
  • + + + {{:: ts('Disable Permission Checks') }} + +
  • +
  • {{:: ts('Default value') }}
  • -
  • +
  • diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js b/ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js index aacb628252..b17c029442 100644 --- a/ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js +++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiField.component.js @@ -100,11 +100,18 @@ return defn; }; + // Get the api entity this field belongs to + this.getEntity = function() { + return afGui.getEntity(ctrl.container.getFieldEntityType(ctrl.node.name)); + }; + $scope.getOriginalLabel = function() { + // Use afform entity if available (e.g. "Individual1") if (ctrl.container.getEntityName()) { return ctrl.editor.getEntity(ctrl.container.getEntityName()).label + ': ' + ctrl.getDefn().label; } - return afGui.getEntity(ctrl.container.getFieldEntityType(ctrl.node.name)).label + ': ' + ctrl.getDefn().label; + // Use generic entity (e.g. "Contact") + return ctrl.getEntity().label + ': ' + ctrl.getDefn().label; }; $scope.hasOptions = function() { @@ -217,6 +224,10 @@ getSet('required', !getSet('required')); }; + $scope.toggleSkipPermissions = function() { + getSet('skip_permissions', !getSet('skip_permissions')); + }; + $scope.toggleHelp = function(position) { getSet('help_' + position, $scope.propIsset('help_' + position) ? null : (ctrl.getDefn()['help_' + position] || ts('Enter text'))); }; diff --git a/ext/afform/admin/ang/afGuiEditor/inputType/Existing.html b/ext/afform/admin/ang/afGuiEditor/inputType/Existing.html new file mode 100644 index 0000000000..d2538363fd --- /dev/null +++ b/ext/afform/admin/ang/afGuiEditor/inputType/Existing.html @@ -0,0 +1,8 @@ +
    +
    + +
    + +
    +
    +
    diff --git a/ext/afform/core/Civi/Afform/AfformMetadataInjector.php b/ext/afform/core/Civi/Afform/AfformMetadataInjector.php index ca20b3ac78..be6cc1a16c 100644 --- a/ext/afform/core/Civi/Afform/AfformMetadataInjector.php +++ b/ext/afform/core/Civi/Afform/AfformMetadataInjector.php @@ -11,6 +11,7 @@ namespace Civi\Afform; +use Civi\Api4\Utils\CoreUtil; use CRM_Afform_ExtensionUtil as E; /** @@ -41,7 +42,7 @@ class AfformMetadataInjector { // Each field can be nested within a fieldset, a join or a block foreach (pq('af-field', $doc) as $afField) { /** @var \DOMElement $afField */ - $action = 'create'; + $action = 'update'; $joinName = pq($afField)->parents('[af-join]')->attr('af-join'); if ($joinName) { self::fillFieldMetadata($joinName, $action, $afField); @@ -178,6 +179,14 @@ class AfformMetadataInjector { break; } } + // Id field for selecting existing entity + if ($field['name'] === CoreUtil::getIdFieldName($entityName)) { + $entityTitle = CoreUtil::getInfoItem($entityName, 'title'); + $field['input_type'] = 'Existing'; + $field['entity'] = $entityName; + $field['label'] = E::ts('Existing %1', [1 => $entityTitle]); + $field['input_attrs']['placeholder'] = E::ts('Select %1', [1 => $entityTitle]); + } // If this is an implicit join, get new field from fk entity if ($field['name'] !== $fieldName && $field['fk_entity']) { $params['where'] = [['name', '=', substr($fieldName, 1 + strrpos($fieldName, '.'))]]; diff --git a/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php b/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php index 44c29051e7..2b5335f475 100644 --- a/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php +++ b/ext/afform/core/Civi/Api4/Subscriber/AutocompleteSubscriber.php @@ -38,7 +38,7 @@ class AutocompleteSubscriber implements EventSubscriberInterface { $apiRequest = $event->getApiRequest(); if (is_object($apiRequest) && is_a($apiRequest, 'Civi\Api4\Generic\AutocompleteAction')) { $formName = $apiRequest->getFormName(); - if (!$formName || !str_starts_with('afform:', $formName) || !strpos(':', $apiRequest->getFieldName() ?: '')) { + if (!str_starts_with((string) $formName, 'afform:') || !strpos((string) $apiRequest->getFieldName(), ':')) { return; } [$entityName, $fieldName] = explode(':', $apiRequest->getFieldName()); @@ -53,11 +53,12 @@ class AutocompleteSubscriber implements EventSubscriberInterface { } $formDataModel = new FormDataModel($afform['layout']); $entity = $formDataModel->getEntity($entityName); - $field = $entity['fields'][$fieldName] ?? NULL; - if ($field) { - $apiRequest->setCheckPermissions(empty($field['defn']['bypass_permission'])); - $apiRequest->setSavedSearch($field['defn']['saved_search'] ?? NULL); + $defn = []; + if (!empty($entity['fields'][$fieldName]['defn'])) { + $defn = \CRM_Utils_JS::decode($entity['fields'][$fieldName]['defn']); } + $apiRequest->setCheckPermissions(empty($defn['skip_permissions'])); + $apiRequest->setSavedSearch($defn['saved_search'] ?? NULL); } } diff --git a/ext/afform/core/ang/af/fields/Existing.html b/ext/afform/core/ang/af/fields/Existing.html new file mode 100644 index 0000000000..10855d4927 --- /dev/null +++ b/ext/afform/core/ang/af/fields/Existing.html @@ -0,0 +1 @@ +