From a541a50fe7dc7e6c339e68d994538031bc33502a Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 12 Mar 2024 21:01:38 +0200 Subject: [PATCH] CFM-274_Breadcrumps_fixes (#171) * Set the Current CO ID for models with dynamic validation rules in AppController. * External Identities associations to MVEAs * Improve FieldHelper:SourceControl * Fix breadcrumps failing when trying to add new MVEA * setCurCoId only if a coId is available * Fix action checking in Breadcrumbs component --- app/src/Controller/AppController.php | 16 ++++++++++++ .../Component/BreadcrumbComponent.php | 19 +++++++++----- .../ExternalIdentitySourcesController.php | 25 ------------------- app/src/Controller/StandardApiController.php | 16 ------------ app/src/Lib/Util/StringUtilities.php | 6 ++++- app/src/Model/Table/AdHocAttributesTable.php | 8 +++++- app/src/Model/Table/EmailAddressesTable.php | 10 ++++++-- app/src/Model/Table/IdentifiersTable.php | 12 ++++++--- app/src/Model/Table/NamesTable.php | 8 ++++-- app/src/Model/Table/TelephoneNumbersTable.php | 11 ++++++-- app/src/View/Helper/FieldHelper.php | 21 ++++++++++------ 11 files changed, 86 insertions(+), 66 deletions(-) diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php index d8665cd9a..8b7562454 100644 --- a/app/src/Controller/AppController.php +++ b/app/src/Controller/AppController.php @@ -117,6 +117,22 @@ public function beforeFilter(\Cake\Event\EventInterface $event) { // Determine the requested CO $this->setCO(); + + // We need to manually set the Current CO ID for models with dynamic validation rules. + // Plugins can implement calculateRequestedCOID() to tell + // AppController what the current CO is, we then pass that information + // manually here. + + // It's not ideal to have a hardcoded list of models, but we don't have + // a better solution at the moment. + + if($this->getCOID() !== null) { + foreach(['Addresses', 'Names', 'TelephoneNumbers'] as $m) { + $Table = TableRegistry::getTableLocator()->get($m); + + $Table->setCurCoId($this->getCOID()); + } + } if(isset($this->RegistryAuth)) { // Components might not be loaded on error, so check diff --git a/app/src/Controller/Component/BreadcrumbComponent.php b/app/src/Controller/Component/BreadcrumbComponent.php index 3c4d994ae..8cf6c44f1 100644 --- a/app/src/Controller/Component/BreadcrumbComponent.php +++ b/app/src/Controller/Component/BreadcrumbComponent.php @@ -181,26 +181,27 @@ public function injectPrimaryLink(object $link, bool $index=true, string $linkLa if(!empty($link->plugin)) { // eg: "CoreEnroller.AttributeCollectors" - $modelPath = $link->plugin . "." . $modelsName; + $modelPath = $link->plugin . '.' . $modelsName; } // Construct the getContains function name $requestAction = $this->getController()->getRequest()->getParam('action'); + $mappedRequestAction = $requestAction; // In the case we are dealing with non-standard actions we need to fallback to a standard one // in order to get access to the contain array. We will use the permissions to decide which - // action to fallback to + // action to fall back to if(!in_array($requestAction, [ 'index', 'view', 'delete', 'add', 'edit' ])) { $permissionsArray = $this->getController()->RegistryAuth->calculatePermissionsForView($requestAction); $id = $this->getController()->getRequest()->getParam('pass')[0] ?? null; if (isset($id)) { - $requestAction = ( isset($permissionsArray['edit']) && $permissionsArray['edit'] ) ? 'edit' : 'view'; + $mappedRequestAction = ( isset($permissionsArray['edit']) && $permissionsArray['edit'] ) ? 'edit' : 'view'; } else { - $requestAction = 'index'; + $mappedRequestAction = 'index'; } } - $containsList = "get" . ucfirst($requestAction) . "Contains"; + $containsList = 'get' . ucfirst($mappedRequestAction) . 'Contains'; $linkTable = TableRegistry::getTableLocator()->get($modelPath); $contain = method_exists($linkTable, $containsList) ? $linkTable->$containsList() : []; @@ -237,7 +238,13 @@ public function injectPrimaryLink(object $link, bool $index=true, string $linkLa // Find the allowed action $breadcrumbAction = method_exists($linkObj, 'isReadOnly') ? ($linkObj->isReadOnly() ? 'view' : 'edit') : - 'edit'; + $mappedRequestAction; + + // We specifically need to check for the add action + if($mappedRequestAction == 'add') { + $breadcrumbAction = 'add'; + } + // The action in the following injectParents dictates the action here [$title,,] = StringUtilities::entityAndActionToTitle($linkObj, $modelPath, $breadcrumbAction); diff --git a/app/src/Controller/ExternalIdentitySourcesController.php b/app/src/Controller/ExternalIdentitySourcesController.php index 5e8e9da38..3ba47ae14 100644 --- a/app/src/Controller/ExternalIdentitySourcesController.php +++ b/app/src/Controller/ExternalIdentitySourcesController.php @@ -35,31 +35,6 @@ use Cake\ORM\TableRegistry; class ExternalIdentitySourcesController extends StandardPluggableController { - /** - * Perform Cake Controller initialization. - * - * @since COmanage Registry v5.0.0 - */ - - public function initialize(): void { - parent::initialize(); - - // We need to manually set the Current CO ID for models with dynamic - // validation rules. This is ordinarily done by AppController, but - // AppController doesn't know how to figure out what CO an API request - // maps to. Plugins can implement calculateRequestedCOID() to tell - // AppController what the current CO is, we then pass that information - // manually here. - - // It's not ideal to have a hardcoded list of models, but we don't have - // a better solution at the moment. - - foreach(['Addresses', 'Names', 'TelephoneNumbers'] as $m) { - $Table = TableRegistry::getTableLocator()->get($m); - - $Table->setCurCoId($this->getCOID()); - } - } public $paginate = [ 'order' => [ diff --git a/app/src/Controller/StandardApiController.php b/app/src/Controller/StandardApiController.php index c3d039079..c3947b67d 100644 --- a/app/src/Controller/StandardApiController.php +++ b/app/src/Controller/StandardApiController.php @@ -43,22 +43,6 @@ class StandardApiController extends AppController { public function initialize(): void { parent::initialize(); - // We need to manually set the Current CO ID for models with dynamic - // validation rules. This is ordinarily done by AppController, but - // AppController doesn't know how to figure out what CO an API request - // maps to. Plugins can implement calculateRequestedCOID() to tell - // AppController what the current CO is, we then pass that information - // manually here. - - // It's not ideal to have a hardcoded list of models, but we don't have - // a better solution at the moment. - - foreach(['Addresses', 'Names', 'TelephoneNumbers'] as $m) { - $Table = TableRegistry::getTableLocator()->get($m); - - $Table->setCurCoId($this->getCOID()); - } - // We want API auth, not Web Auth $this->RegistryAuth->setConfig('apiUser', true); } diff --git a/app/src/Lib/Util/StringUtilities.php b/app/src/Lib/Util/StringUtilities.php index 5b9249846..885288112 100644 --- a/app/src/Lib/Util/StringUtilities.php +++ b/app/src/Lib/Util/StringUtilities.php @@ -180,7 +180,11 @@ public static function entityAndActionToTitle($entity, } // Add/Edit/View - if(method_exists($linkTable, 'generateDisplayField')) { + // The MVEA Models have a entityId. The one from the parent model. + // We need to have a condition for this and exclude it. + if($entity->id !== null + && $action != 'add' + && method_exists($linkTable, 'generateDisplayField')) { // We don't use a trait for this since each table will implement different logic $title = __d($domain, $msgId, $linkTable->generateDisplayField($entity)); diff --git a/app/src/Model/Table/AdHocAttributesTable.php b/app/src/Model/Table/AdHocAttributesTable.php index 0e02e5e35..922535577 100644 --- a/app/src/Model/Table/AdHocAttributesTable.php +++ b/app/src/Model/Table/AdHocAttributesTable.php @@ -42,6 +42,7 @@ class AdHocAttributesTable extends Table { use \App\Lib\Traits\TableMetaTrait; use \App\Lib\Traits\ValidationTrait; use \App\Lib\Traits\SearchFilterTrait; + use \App\Lib\Traits\QueryModificationTrait; /** * Provide the default layout @@ -73,13 +74,18 @@ public function initialize(array $config): void { $this->belongsTo('PersonRoles'); $this->belongsTo('ExternalIdentities'); $this->belongsTo('ExternalIdentityRoles'); - + $this->belongsTo('ExtIdentitySourceRecords') + ->setClassName('ExtIdentitySourceRecords') + ->setForeignKey('source_ad_hoc_attribute_id') + ->setProperty('source_ad_hoc_attribute'); + $this->setDisplayField('tag'); $this->setPrimaryLink(['external_identity_id', 'external_identity_role_id', 'person_id', 'person_role_id']); $this->setRequiresCO(true); $this->setRedirectGoal('self'); $this->setAllowLookupPrimaryLink(['unfreeze']); + $this->setEditContains(['ExternalIdentities', 'ExtIdentitySourceRecords']); $this->setPermissions([ // Actions that operate over an entity (ie: require an $id) diff --git a/app/src/Model/Table/EmailAddressesTable.php b/app/src/Model/Table/EmailAddressesTable.php index e1a97431f..0cd60fe6d 100644 --- a/app/src/Model/Table/EmailAddressesTable.php +++ b/app/src/Model/Table/EmailAddressesTable.php @@ -44,6 +44,7 @@ class EmailAddressesTable extends Table { use \App\Lib\Traits\TypeTrait; use \App\Lib\Traits\ValidationTrait; use \App\Lib\Traits\SearchFilterTrait; + use \App\Lib\Traits\QueryModificationTrait; // Default "out of the box" types for this model. Entries here should be // given a default localization in app/resources/locales/*/defaultType.po @@ -88,7 +89,11 @@ public function initialize(array $config): void { $this->belongsTo('People'); $this->belongsTo('ExternalIdentities'); $this->belongsTo('Types'); - + $this->belongsTo('ExtIdentitySourceRecords') + ->setClassName('ExtIdentitySourceRecords') + ->setForeignKey('source_email_address_id') + ->setProperty('source_email_address'); + $this->setDisplayField('mail'); $this->setPrimaryLink(['external_identity_id', 'person_id']); @@ -96,7 +101,8 @@ public function initialize(array $config): void { $this->setRequiresCO(true); $this->setRedirectGoal('self'); $this->setAllowLookupPrimaryLink(['unfreeze']); - + $this->setEditContains(['ExternalIdentities', 'ExtIdentitySourceRecords']); + $this->setAutoViewVars([ 'types' => [ 'type' => 'type', diff --git a/app/src/Model/Table/IdentifiersTable.php b/app/src/Model/Table/IdentifiersTable.php index a0578eff7..7b3b3d2cf 100644 --- a/app/src/Model/Table/IdentifiersTable.php +++ b/app/src/Model/Table/IdentifiersTable.php @@ -47,7 +47,8 @@ class IdentifiersTable extends Table { use \App\Lib\Traits\TypeTrait; use \App\Lib\Traits\ValidationTrait; use \App\Lib\Traits\SearchFilterTrait; - + use \App\Lib\Traits\QueryModificationTrait; + // Default "out of the box" types for this model. Entries here should be // given a default localization in app/resources/locales/*/defaultType.po protected $defaultTypes = [ @@ -104,14 +105,19 @@ public function initialize(array $config): void { $this->belongsTo('People'); $this->belongsTo('ProvisioningTargets'); $this->belongsTo('Types'); - + $this->belongsTo('ExtIdentitySourceRecords') + ->setClassName('ExtIdentitySourceRecords') + ->setForeignKey('source_identifier_id') + ->setProperty('source_identifier'); + $this->setDisplayField('identifier'); $this->setPrimaryLink(['external_identity_id', 'group_id', 'person_id']); $this->setRequiresCO(true); $this->setRedirectGoal('self'); $this->setAllowLookupPrimaryLink(['unfreeze']); - + $this->setEditContains(['ExternalIdentities', 'ExtIdentitySourceRecords']); + $this->setAutoViewVars([ 'types' => [ 'type' => 'type', diff --git a/app/src/Model/Table/NamesTable.php b/app/src/Model/Table/NamesTable.php index df1c2955e..60e218933 100644 --- a/app/src/Model/Table/NamesTable.php +++ b/app/src/Model/Table/NamesTable.php @@ -51,6 +51,8 @@ class NamesTable extends Table { use \App\Lib\Traits\TypeTrait; use \App\Lib\Traits\ValidationTrait; use \App\Lib\Traits\SearchFilterTrait; + use \App\Lib\Traits\QueryModificationTrait; + // Default "out of the box" types for this model. Entries here should be // given a default localization in app/resources/locales/*/defaultType.po @@ -103,10 +105,12 @@ public function initialize(array $config): void { $this->setPrimaryLink(['external_identity_id', 'person_id']); $this->setAllowLookupPrimaryLink(['primary', 'unfreeze']); $this->setRequiresCO(true); - // Models that AcceptCoId should be expicitly added to StandardApiController::initialize() + // Models that AcceptCoId should be explicitly added to StandardApiController::initialize() $this->setAcceptsCoId(true); $this->setRedirectGoal('self'); - + $this->setEditContains(['ExternalIdentities', 'ExtIdentitySourceRecords']); + + $this->setAutoViewVars([ 'languages' => [ 'type' => 'enum', diff --git a/app/src/Model/Table/TelephoneNumbersTable.php b/app/src/Model/Table/TelephoneNumbersTable.php index 78f3013fc..baed829d5 100644 --- a/app/src/Model/Table/TelephoneNumbersTable.php +++ b/app/src/Model/Table/TelephoneNumbersTable.php @@ -45,6 +45,7 @@ class TelephoneNumbersTable extends Table { use \App\Lib\Traits\TypeTrait; use \App\Lib\Traits\ValidationTrait; use \App\Lib\Traits\SearchFilterTrait; + use \App\Lib\Traits\QueryModificationTrait; // Default "out of the box" types for this model. Entries here should be // given a default localization in app/resources/locales/*/defaultType.po @@ -89,7 +90,11 @@ public function initialize(array $config): void { $this->belongsTo('ExternalIdentities'); $this->belongsTo('ExternalIdentityRoles'); $this->belongsTo('Types'); - + $this->belongsTo('ExtIdentitySourceRecords') + ->setClassName('ExtIdentitySourceRecords') + ->setForeignKey('source_telephone_number_id') + ->setProperty('source_telephone_number'); + $this->setDisplayField('number'); $this->setPrimaryLink(['external_identity_id', 'external_identity_role_id', 'person_id', 'person_role_id']); @@ -98,7 +103,9 @@ public function initialize(array $config): void { $this->setAcceptsCoId(true); $this->setRedirectGoal('self'); $this->setAllowLookupPrimaryLink(['unfreeze']); - + $this->setEditContains(['ExternalIdentities', 'ExtIdentitySourceRecords']); + + $this->setAutoViewVars([ 'types' => [ 'type' => 'type', diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index c8bb4e409..0ff99a9bc 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -521,27 +521,32 @@ public function sourceControl($entity): string { // In most cases $sourceModelName = $modelName, but not for PersonRoles $sourceModelName = substr(StringUtilities::foreignKeyToClassName($sourceFK), 6); - $linkHtml = ""; + $linkHtml = '
'; if(!empty($entity->$sourceFK)) { - $linkHtml = $this->Html->Link( + $linkHtml .= $this->Html->Link( title: __d('controller', $sourceModelName, [1]), url: [ 'controller' => $sourceModelName, 'action' => 'view', $entity->$sourceFK ] - ) . ", " . - $this->Html->Link( + ); + } + + if(!empty($entity->$sourceEntityName)) { + $linkHtml .= ', ' . $this->Html->Link( title: __d('controller', 'ExternalIdentities', [1]), url: [ - 'controller' => 'external_identities', - 'action' => 'view', - $entity->$sourceEntityName->external_identity_id - ] + 'controller' => 'external_identities', + 'action' => 'view', + $entity->$sourceEntityName->external_identity_id + ] ); } + $linkHtml .= '
'; + return $this->startLine() . $this->formNameDiv( fieldName: $sourceFK,