Skip to content

Commit

Permalink
Various fixes for Provisioning status (CFM-26)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benn Oshrin committed Mar 17, 2026
1 parent 22d94c0 commit 2d1fccd
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 92 deletions.
12 changes: 12 additions & 0 deletions app/resources/locales/en_US/field.po
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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"

Expand Down
3 changes: 3 additions & 0 deletions app/resources/locales/en_US/information.po
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down
71 changes: 33 additions & 38 deletions app/src/Controller/ProvisioningTargetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
class ProvisioningTargetsController extends StandardPluggableController {
protected array $paginate = [
'order' => [
'ProvisioningTargets.description' => 'asc'
'ProvisioningTargets.ordr' => 'asc'
]
];

Expand All @@ -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.
*
Expand Down Expand Up @@ -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));
}
}
}
111 changes: 63 additions & 48 deletions app/src/Model/Table/ProvisioningTargetsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}

Expand Down
16 changes: 10 additions & 6 deletions app/templates/ProvisioningTargets/status.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
<tr>
<td class="actions"></td>
<th><?= __d('controller', 'ProvisioningTargets', [1]); ?></th>
<th><?= __d('field', 'status'); ?></th>
<th><?= __d('field', 'comment'); ?></th>
<th><?= __d('field', 'ProvisioningTargets.status.live'); ?></th>
<th><?= __d('field', 'ProvisioningTargets.comment.live'); ?></th>
<th><?= __d('field', 'ProvisioningTargets.status.last'); ?></th>
<th><?= __d('field', 'ProvisioningTargets.comment.last'); ?></th>
<th><?= __d('controller', 'Identifiers', [1]); ?></th>
<th><?= __d('field', 'timestamp'); ?></th>
</tr>
Expand All @@ -59,7 +61,7 @@
<?php
// Build the row actions
$action_args = array();
$action_args['vv_attr_id'] = $p['target']->id;
$action_args['vv_attr_id'] = $p['target']->id;
$action_args['vv_actions'] = [
[
'order' => $this->Menu->getMenuOrder('Default'),
Expand Down Expand Up @@ -97,10 +99,12 @@
?>
</div>
</td>
<td><?= $p['target']->description; ?></td>
<td><?= filter_var($p['target']->description, FILTER_SANITIZE_SPECIAL_CHARS); ?></td>
<td><?= __d('enumeration', 'ProvisioningStatusEnum.'.$p['status']); ?></td>
<td><?= $p['comment']; ?></td>
<td><?= $p['identifier'] ?? ""; ?></td>
<td><?= filter_var($p['comment'], FILTER_SANITIZE_SPECIAL_CHARS); ?></td>
<td><?= __d('enumeration', 'ProvisioningStatusEnum.'.$p['laststatus']); ?></td>
<td><?= filter_var($p['lastcomment'], FILTER_SANITIZE_SPECIAL_CHARS); ?></td>
<td><?= filter_var($p['identifier'] ?? "", FILTER_SANITIZE_SPECIAL_CHARS); ?></td>
<td><?= !empty($p['timestamp']) ? $this->Time->nice($p['timestamp'], $vv_tz) : ""; ?></td>
</tr>
<?php endforeach; ?>
Expand Down

0 comments on commit 2d1fccd

Please sign in to comment.