diff --git a/app/resources/locales/en_US/field.po b/app/resources/locales/en_US/field.po index 5afbfafcb..e8450d43c 100644 --- a/app/resources/locales/en_US/field.po +++ b/app/resources/locales/en_US/field.po @@ -956,6 +956,12 @@ msgstr "Subject Object Type" msgid "ProvisioningHistoryRecords.subjectid" msgstr "Subject Object ID" +msgid "ProvisioningTargets.comment.last" +msgstr "Last Comment" + +msgid "ProvisioningTargets.comment.live" +msgstr "Comment" + msgid "ProvisioningTargets.max_retry" msgstr "Max Retries" @@ -980,6 +986,12 @@ msgstr "If the provisioning action fails, it will be automatically retried after msgid "ProvisioningTargets.status" msgstr "Provisioning Mode" +msgid "ProvisioningTargets.status.last" +msgstr "Last Status" + +msgid "ProvisioningTargets.status.live" +msgstr "Live Status" + msgid "TelephoneNumbers.formatted_number" msgstr "Telephone Number" diff --git a/app/resources/locales/en_US/information.po b/app/resources/locales/en_US/information.po index 9d2120a65..229813397 100644 --- a/app/resources/locales/en_US/information.po +++ b/app/resources/locales/en_US/information.po @@ -162,6 +162,9 @@ msgstr "This plugin requires no configuration." msgid "plugin.inactive" msgstr "Inactive" +msgid "ProvisioningTargets.status.title" +msgstr "Provisioning Status for {0}" + msgid "state.info" msgstr "{0} successfully {1} to {2}" diff --git a/app/src/Controller/ProvisioningTargetsController.php b/app/src/Controller/ProvisioningTargetsController.php index e150c79c9..c5d4115f6 100644 --- a/app/src/Controller/ProvisioningTargetsController.php +++ b/app/src/Controller/ProvisioningTargetsController.php @@ -38,7 +38,7 @@ class ProvisioningTargetsController extends StandardPluggableController { protected array $paginate = [ 'order' => [ - 'ProvisioningTargets.description' => 'asc' + 'ProvisioningTargets.ordr' => 'asc' ] ]; @@ -56,27 +56,6 @@ public function initialize(): void { $this->Breadcrumb->skipParents(['/^\/provisioning-targets\/status/']); } - /** - * Callback run prior to the request action. - * - * @since COmanage Registry v5.0.0 - * @param EventInterface $event Cake Event - * @return \Cake\Http\Response HTTP Response - */ - - public function beforeFilter(\Cake\Event\EventInterface $event) { - if(!$this->request->is('restful')) { - // Provide additional hints to BreadcrumbsComponent. This needs to be here - // and not in beforeRender because the component beforeRender will run first. - - if($this->request->getParam('action') == 'status') { - $this->Breadcrumb->injectPrimaryLink($this->getPrimaryLink(true)); - } - } - - parent::beforeFilter($event); - } - /** * Register a (re)provisioning job. * @@ -119,24 +98,40 @@ public function reprovision(string $id) { */ public function status() { - // PrimaryLinkTrait - Look up our primary link to see which object type we're - // working with, an also get our CO ID - $link = $this->getPrimaryLink(true); - // Use argument unpacking operator with names parameters in order to make the call more dynamic - $statusCalculateParams = [ - 'coId' => $link->co_id, - // Currently supported function parameters are personId, groupId - Inflector::variable($link->attr) => (int)$link->value - ]; - $statuses = $this->ProvisioningTargets->status(...$statusCalculateParams); - - $this->set('vv_provisioning_statuses', $statuses); + // We support filtering on person_id or group_id. + + $targetModel = 'People'; + $targetFK = 'person_id'; + $targetName = '(?)'; + + if(!empty($this->request->getQuery('group_id'))) { + $targetModel = 'Groups'; + $targetFK = 'group_id'; + } + + $targetID = (int)$this->request->getQuery($targetFK); + + $this->set('vv_provisioning_statuses', $this->ProvisioningTargets->status( + coId: $this->getCOID(), + groupId: $targetFK == 'group_id' ? $targetID : null, + personId: $targetFK == 'person_id' ? $targetID : null + )); + + $this->set('vv_target_fk', $targetFK); + $this->set('vv_target_id', $targetID); if(!$this->request->is('restful')) { - [$title, , ] = StringUtilities::entityAndActionToTitle(null, - 'provisioning', - $this->request->getParam('action')); - $this->set('vv_title', $title); + $Model = TableRegistry::getTableLocator()->get($targetModel); + + if($targetModel == 'People') { + $entity = $Model->get($targetID, contain: ['PrimaryName']); + $targetName = $entity->primary_name->full_name; + } else { + $entity = $Model->get($targetID); + $targetName = $entity->name; + } + + $this->set('vv_title', __d('information', 'ProvisioningTargets.status.title', $targetName)); } } } \ No newline at end of file diff --git a/app/src/Model/Table/ProvisioningTargetsTable.php b/app/src/Model/Table/ProvisioningTargetsTable.php index 58d80b40d..4fa4aeec1 100644 --- a/app/src/Model/Table/ProvisioningTargetsTable.php +++ b/app/src/Model/Table/ProvisioningTargetsTable.php @@ -51,6 +51,7 @@ class ProvisioningTargetsTable extends Table { use \App\Lib\Traits\PermissionsTrait; use \App\Lib\Traits\PluggableModelTrait; use \App\Lib\Traits\PrimaryLinkTrait; + use \App\Lib\Traits\QueryModificationTrait; use \App\Lib\Traits\TableMetaTrait; use \App\Lib\Traits\ValidationTrait; @@ -398,6 +399,7 @@ public function provision( * @param int $coId CO ID * @param int $groupId Group ID * @param int $personId Person ID + * @return array Array of provisioning data, per target */ public function status(int $coId, ?int $groupId=null, ?int $personId=null): array { @@ -439,68 +441,81 @@ public function status(int $coId, ?int $groupId=null, ?int $personId=null): arra ]) ->first(); - // If the plugin implements a status() function we'll call it, otherwise - // we'll get the status from ProvisioningHistory. + // There are two types of information we want to return here, live status + // (which requires plugin support) and last result (which is stored in + // ProvisioningHistoryRecords). We want to return both (when available) since + // (for example) the plugin might return "Provisioned" even though the last + // attempt to provision failed for some reason (but a prior one was successful). $PluginModel = TableRegistry::getTableLocator()->get($t->plugin); + $info = [ + 'target' => $t, + // Live status from the plugin + 'status' => ProvisioningStatusEnum::Unknown, + 'comment' => null, + // Record status via ProvisionerHistoryRecords + 'laststatus' => ProvisioningStatusEnum::Unknown, + 'lastcomment' => null, + // timestamp and identifier from the plugin if available, else history + 'timestamp' => null, + 'identifier' => null + ]; + if(method_exists($PluginModel, 'status')) { + // Determine live status from the plugin try { $status = $PluginModel->status(cfg: $t, groupId: $groupId, personId: $personId); - $ret[] = [ - 'target' => $t, - 'status' => $status['status'], - 'comment' => $status['comment'], - 'timestamp' => $status['timestamp'], - 'identifier' => $pkey ? $pkey->identifier : null - ]; + $info['status'] = $status['status']; + $info['comment'] = $status['comment']; + $info['timestamp'] = $status['timestamp']; + $info['identifier'] = $pkey ? $pkey->identifier : null; } catch(\Exception $e) { - $ret[] = [ - 'target' => $t, - 'status' => ProvisioningStatusEnum::Unknown, - 'comment' => $e->getMessage() - ]; + $info['comment'] = $e->getMessage(); } + } + + // Now check history + $subjectFK = null; + $subjectID = null; + + if(!empty($personId)) { + $subjectFK = 'person_id'; + $subjectID = $personId; + } elseif(!empty($groupId)) { + $subjectFK = 'group_id'; + $subjectID = $groupId; } else { - $subjectFK = null; - $subjectID = null; - - if(!empty($personId)) { - $subjectFK = 'person_id'; - $subjectID = $personId; - } elseif(!empty($groupId)) { - $subjectFK = 'group_id'; - $subjectID = $groupId; - } else { - throw new \InvalidArgumentException("NOT IMPKEMENTED"); + throw new \InvalidArgumentException("NOT IMPKEMENTED"); + } + + $rec = $this->ProvisioningHistoryRecords->find() + ->where([ + 'provisioning_target_id' => $t->id, + $subjectFK => $subjectID + ]) + ->orderBy(['id' => 'DESC']) + ->first(); + + if(!empty($rec)) { + $info['laststatus'] = $rec->status; + $info['lastcomment'] = $rec->comment; + + if(!$info['identifier']) { + $info['identifier'] = $pkey ? $pkey->identifier : null; } - - $rec = $this->ProvisioningHistoryRecords->find() - ->where([ - 'provisioning_target_id' => $t->id, - $subjectFK => $subjectID - ]) - ->orderBy(['id' => 'DESC']) - ->first(); - - if(!empty($rec)) { - $ret[] = [ - 'target' => $t, - 'status' => $rec->status, - 'comment' => $rec->comment, - 'identifier' => $pkey ? $pkey->identifier : null, - 'timestamp' => $rec->created - ]; - } else { - $ret[] = [ - 'target' => $t, - 'status' => ProvisioningStatusEnum::NotProvisioned, - 'comment' => __d('enumeration', 'ProvisioningStatusEnum.'.ProvisioningStatusEnum::NotProvisioned) - ]; + + if(!$info['timestamp']) { + $info['timestamp'] = $rec->created; } + } else { + $info['laststatus'] = ProvisioningStatusEnum::NotProvisioned; + $info['lastcomment'] = __d('enumeration', 'ProvisioningStatusEnum.'.ProvisioningStatusEnum::NotProvisioned); } + + $ret[] = $info; } } diff --git a/app/templates/ProvisioningTargets/status.php b/app/templates/ProvisioningTargets/status.php index 7344de06f..8eb3c5b69 100644 --- a/app/templates/ProvisioningTargets/status.php +++ b/app/templates/ProvisioningTargets/status.php @@ -43,8 +43,10 @@ - - + + + + @@ -59,7 +61,7 @@ id; + $action_args['vv_attr_id'] = $p['target']->id; $action_args['vv_actions'] = [ [ 'order' => $this->Menu->getMenuOrder('Default'), @@ -97,10 +99,12 @@ ?> - description; ?> + description, FILTER_SANITIZE_SPECIAL_CHARS); ?> - - + + + + Time->nice($p['timestamp'], $vv_tz) : ""; ?>