diff --git a/app/config/schema/schema.json b/app/config/schema/schema.json index 86ea747fe..4be5748c6 100644 --- a/app/config/schema/schema.json +++ b/app/config/schema/schema.json @@ -661,6 +661,7 @@ "plugin": {}, "ordr": {}, "actor_type": { "type": "string", "size": 2 }, + "enable_person_find": { "type": "boolean" }, "approver_group_id": { "type": "integer", "foreignkey": { "table": "groups", "column": "id" }}, "message_template_id": {}, "redirect_on_handoff": { "type": "string", "size": 256 }, diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po index 56d7fb893..6107cfac1 100644 --- a/app/resources/locales/en_US/field.po +++ b/app/resources/locales/en_US/field.po @@ -456,6 +456,12 @@ msgstr "Limit Global Search Scope" msgid "CoSettings.search_global_limited_models.desc" msgstr "If true, Global Search will only search Names, Email Addresses, and Identifiers. This may result in faster searches for larger deployments." +msgid "EnrollmentFlowSteps.enable_person_find" +msgstr "Enable People Picker for Self Service" + +msgid "EnrollmentFlowSteps.enable_person_find.desc" +msgstr "Enable people picker for self-service enrollments, see Registry Technical Manual for privacy considerations" + msgid "EnrollmentFlowSteps.actor_type" msgstr "Actor Type" diff --git a/app/src/Controller/ApiV2Controller.php b/app/src/Controller/ApiV2Controller.php index 435b156f7..d41eef857 100644 --- a/app/src/Controller/ApiV2Controller.php +++ b/app/src/Controller/ApiV2Controller.php @@ -29,14 +29,15 @@ namespace App\Controller; -use Cake\Controller\Controller; -use InvalidArgumentException; +use App\Lib\Enum\EnrollmentAuthzEnum; use Cake\Chronos\Chronos; +use Cake\Controller\Controller; +use Cake\Event\EventInterface; use Cake\Http\Exception\BadRequestException; use Cake\Log\Log; use Cake\ORM\TableRegistry; use Cake\Utility\Inflector; - +use InvalidArgumentException; use \App\Lib\Enum\ProvisioningContextEnum; use \App\Lib\Enum\SuspendableStatusEnum; @@ -410,4 +411,53 @@ public function view($id = null) { public function pick() { $this->dispatchIndex(mode: 'picker'); } + + /** + * Indicate whether this Controller will handle some or all authnz. + * + * @param EventInterface $event Cake event, ie: from beforeFilter + * @return string "no", "open", "authz", "yes", or "notauth" + * @since COmanage Registry v5.2.0 + */ + public function willHandleAuth(\Cake\Event\EventInterface $event): string + { + $request = $this->getRequest(); + $reqAction = $request->getParam('action'); + $session = $request->getSession(); + $mode = 'no'; + + $auth = $session->read('Auth'); + + // Calculate people picker permissions on the fly for an enrollment flow/petition + if( + $this->name == 'People' + && $reqAction == 'pick' + && !empty($request->getQuery('petition_id')) + ) { + $petitionId = (int)$request->getQuery('petition_id'); + // We need to check if this is part of an Enrollment Flow + $Petitions = TableRegistry::getTableLocator()->get('Petitions'); + + // Pull the Petition to find its CO + $petition = $Petitions->get($petitionId, ['contain' => ['EnrollmentFlows' => ['EnrollmentFlowSteps']]]); + + // We need to check the Petitioner Authorization. + $hasAuthorizedUser = false; + if ($petition->enrollment_flow->authz_type == EnrollmentAuthzEnum::AuthUser) { + $hasAuthorizedUser = !empty($auth['external']['user']); + } else { + // This will be the no authorization use case. + $hasAuthorizedUser = true; + } + + foreach ($petition->enrollment_flow->enrollment_flow_steps as $step) { + if ($step->plugin == 'CoreEnroller.AttributeCollectors') { + $mode = $hasAuthorizedUser && $step->enable_person_find ? 'yes' : 'no'; + } + } + } + + // Apply standard behavior + return $mode; + } } \ No newline at end of file diff --git a/app/src/Controller/Component/RegistryAuthComponent.php b/app/src/Controller/Component/RegistryAuthComponent.php index 5df86abcc..f1098d43e 100644 --- a/app/src/Controller/Component/RegistryAuthComponent.php +++ b/app/src/Controller/Component/RegistryAuthComponent.php @@ -325,7 +325,7 @@ protected function calculatePermission(string $action, ?int $id=null): bool { * Obtain the permission set for this request. * * @since COmanage Registry v5.0.0 - * @param int $id Subject ID, if applicable + * @param int|null $id Subject ID, if applicable * @return array Array of actions and authorized roles */ @@ -719,8 +719,8 @@ public function getPersonID(int $coId): ?int { * Obtain the set of permissions as provided by the table. * * @since COmanage Registry v5.0.0 - * @param table $table Cake Table - * @param int $id Entity ID, if applicable + * @param table $table Cake Table + * @param int|null $id Entity ID, if applicable * @return array Table permissions */ @@ -857,7 +857,7 @@ public function isAuthenticatedUser(): bool { * Determine if the current user is a CO Administrator. * * @since COmanage Registry v5.0.0 - * @param int $coId CO ID + * @param int|null $coId CO ID * @return bool True if the current user is a CO Administrator */ diff --git a/app/src/Controller/PeopleController.php b/app/src/Controller/PeopleController.php index 5d529a590..f88d7fbcb 100644 --- a/app/src/Controller/PeopleController.php +++ b/app/src/Controller/PeopleController.php @@ -30,6 +30,7 @@ namespace App\Controller; // XXX not doing anything with Log yet +use Cake\Event\EventInterface; use Cake\Log\Log; use Cake\ORM\TableRegistry; use http\QueryString; diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 5e674a06c..12e3a508f 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -32,6 +32,8 @@ use App\Lib\Enum\DateTypeEnum; use App\Lib\Util\StringUtilities; use Cake\I18n\FrozenTime; +use Cake\ORM\Table; +use Cake\ORM\TableRegistry; use Cake\Utility\Inflector; use Cake\View\Helper; use DOMDocument; @@ -548,6 +550,36 @@ public function getReqFields(): array return $this->reqFields; } + /** + * Get reference to the Table Object + * + * @param string $tableName + * + * @return Table + * @since COmanage Registry v5.2.0 + */ + public function getTable(string $tableName): Table + { + return TableRegistry::getTableLocator()->get($tableName); + } + + /** + * Get attribute collectors configuration for a specific enrollment flow step + * + * @param int $stepId The ID of the enrollment flow step + * @return array The attribute collectors configuration array containing enrollment attributes + * @since COmanage Registry v5.2.0 + */ + public function getAttributeCollectorsForStep(int $stepId): array + { + $AttributeCollectors = $this->getTable('CoreEnroller.AttributeCollectors'); + return $AttributeCollectors->find() + ->where(['enrollment_flow_step_id' => $stepId]) + ->contain(['EnrollmentAttributes']) + ->first() + ->toArray(); + } + /** * For the records that have a value like co_x.value, and we want to handle * the value separate from the field diff --git a/app/src/View/Helper/PetitionHelper.php b/app/src/View/Helper/PetitionHelper.php index be426a30d..c4ac48521 100644 --- a/app/src/View/Helper/PetitionHelper.php +++ b/app/src/View/Helper/PetitionHelper.php @@ -76,7 +76,7 @@ public function populateAutoViewVars(): void { // XXX Find the co id foreach ( - $this->enrollmentAttributesTable->calculateAutoViewVars($this->petition?->enrollment_flow?->co_id,$this->entity) as $vvar => $value + $this->enrollmentAttributesTable->calculateAutoViewVars($this->petition?->enrollment_flow?->co_id, $this->entity) as $vvar => $value ) { $this->getView()->set($vvar, $value); } diff --git a/app/templates/CoSettings/fields.inc b/app/templates/CoSettings/fields.inc index 4b51f4165..75231447b 100644 --- a/app/templates/CoSettings/fields.inc +++ b/app/templates/CoSettings/fields.inc @@ -96,32 +96,32 @@ if($vv_action == 'edit') { 'fieldName' => 'search_global_limited_models' ]]); - print $this->element('form/listItem', [ - 'arguments' => [ - 'fieldName' => 'person_picker_display_fields', - 'labelIsTextOnly' => true, - 'groupedControls' => [ - // each key is the fieldName of the control we are going to create - 'person_picker_email_address_type_id' => [ - 'fieldOptions' => [ - 'label' => __d('field', 'mail'), - 'empty' => '(' . __d('operation', 'all') . ')', -// 'all' => '(' . __d('operation', 'all') . ')' - ], - ], - 'person_picker_identifier_type_id' => [ - 'fieldOptions' => [ - 'label' => __d('field', 'identifier'), - 'empty' => '(' . __d('operation', 'all') . ')', -// 'all' => '(' . __d('operation', 'all') . ')', - ], - ], - 'person_picker_display_types' => [ - 'singleRowItem' => true, - 'fieldLabel' => __d('field', 'CoSettings.person_picker_display_types') - ] - ], - ]]); +// print $this->element('form/listItem', [ +// 'arguments' => [ +// 'fieldName' => 'person_picker_display_fields', +// 'labelIsTextOnly' => true, +// 'groupedControls' => [ +// // each key is the fieldName of the control we are going to create +// 'person_picker_email_address_type_id' => [ +// 'fieldOptions' => [ +// 'label' => __d('field', 'mail'), +// 'empty' => '(' . __d('operation', 'all') . ')', +//// 'all' => '(' . __d('operation', 'all') . ')' +// ], +// ], +// 'person_picker_identifier_type_id' => [ +// 'fieldOptions' => [ +// 'label' => __d('field', 'identifier'), +// 'empty' => '(' . __d('operation', 'all') . ')', +//// 'all' => '(' . __d('operation', 'all') . ')', +// ], +// ], +// 'person_picker_display_types' => [ +// 'singleRowItem' => true, +// 'fieldLabel' => __d('field', 'CoSettings.person_picker_display_types') +// ] +// ], +// ]]); print $this->element('form/listItem', [ 'arguments' => [ diff --git a/app/templates/EnrollmentFlowSteps/fields.inc b/app/templates/EnrollmentFlowSteps/fields.inc index ffe5137ec..8b831543b 100644 --- a/app/templates/EnrollmentFlowSteps/fields.inc +++ b/app/templates/EnrollmentFlowSteps/fields.inc @@ -69,6 +69,22 @@ if($vv_action == 'add' || $vv_action == 'edit') { ]]); } + // The people picker enable checkbox is only useful for the attribute collection plugin. + if ($vv_obj->plugin === 'CoreEnroller.AttributeCollectors') { + $attributeCollectorConfig = $this->Field->getAttributeCollectorsForStep( $vv_obj->id); + $sponsorAttribute = array_filter( + $attributeCollectorConfig["enrollment_attributes"], + fn($enrollmentAttribute) => $enrollmentAttribute['attribute'] == 'sponsor_person_id' + ); + print $this->element('form/listItem', [ + 'arguments' => [ + 'fieldName' => 'enable_person_find', + 'fieldOptions' => [ + 'readonly' => empty($sponsorAttribute) + ] + ]]); + } + print $this->element('form/listItem', [ 'arguments' => [ 'fieldName' => 'actor_type',