1
0
Files
breadcrumb-the-shire/modules/security/pages/security/checks/edit(default).phtml

260 lines
14 KiB
PHTML

<?php
use MintyPHP\Module\Security\Service\SecurityCheckProcess;
$check = is_array($check ?? null) ? $check : [];
$steps = is_array($steps ?? null) ? $steps : [];
$techItems = is_array($techItems ?? null) ? $techItems : [];
$processState = is_array($processState ?? null) ? $processState : [];
$techState = is_array($techState ?? null) ? $techState : [];
$progress = is_array($progress ?? null) ? $progress : [];
$userNames = is_array($userNames ?? null) ? $userNames : [];
$canEdit = $canEdit ?? false;
$canManage = $canManage ?? false;
$canGenerateReport = $canGenerateReport ?? false;
$reportPdfUrl = (string) ($reportPdfUrl ?? '');
$status = (string) ($status ?? SecurityCheckProcess::STATUS_OPEN);
$readonly = !$canEdit;
$percent = (int) ($progress['percent'] ?? 0);
$doneCount = (int) ($progress['done'] ?? 0);
$totalCount = (int) ($progress['total'] ?? 0);
$completionMeta = static function (array $entry) use ($userNames): string {
if (empty($entry['done'])) {
return '';
}
$parts = [];
$by = (int) ($entry['by'] ?? 0);
if ($by > 0 && isset($userNames[$by]) && $userNames[$by] !== '') {
$parts[] = $userNames[$by];
}
$at = trim((string) ($entry['at'] ?? ''));
if ($at !== '') {
$parts[] = $at;
}
return $parts === [] ? '' : implode(' · ', $parts);
};
?>
<div class="app-details-container">
<section data-tab-panel data-tab-panel-wide>
<?php
$titlebar = [
'title' => t('Security check'),
'backHref' => lurl($closeTarget ?? 'security/checks'),
];
if (!$readonly) {
$titlebar['actions'] = [
[
'label' => t('Save'),
'type' => 'submit',
'form' => 'security-check-form',
'name' => 'action',
'value' => 'save',
'class' => 'primary',
'tone' => 'success',
],
];
}
require templatePath('partials/app-details-titlebar.phtml');
?>
<!-- Summary -->
<div class="security-check-summary">
<dl class="security-check-meta">
<div><dt><?php e(t('Customer')); ?></dt><dd><?php e((string) ($check['debitor_name'] ?? '')); ?> <span class="app-muted">(<?php e((string) ($check['debitor_no'] ?? '')); ?>)</span></dd></div>
<div><dt><?php e(t('Domain')); ?></dt><dd><?php e((string) ($check['domain_url'] ?? ($check['domain_no'] ?? ''))); ?></dd></div>
<div><dt><?php e(t('Software product')); ?></dt><dd><?php e((string) ($check['product_name'] ?? ($check['product_code'] ?? ''))); ?></dd></div>
<div><dt><?php e(t('Owner')); ?></dt><dd><?php e((string) ($check['owner_name'] ?? '—')); ?></dd></div>
<div><dt><?php e(t('Status')); ?></dt><dd><span class="badge" data-variant="<?php e(SecurityCheckProcess::statusVariant($status)); ?>"><?php e(t(SecurityCheckProcess::statusLabel($status))); ?></span></dd></div>
</dl>
</div>
<div class="security-check-progress">
<div class="security-check-progress-bar" role="progressbar" aria-label="<?php e(t('Progress')); ?>" aria-valuenow="<?php e((string) $percent); ?>" aria-valuemin="0" aria-valuemax="100">
<div class="security-check-progress-fill" style="width: <?php e((string) $percent); ?>%"></div>
</div>
<span class="security-check-progress-label"><?php e(t('%d of %d completed', $doneCount, $totalCount)); ?> (<?php e((string) $percent); ?>%)</span>
</div>
<?php if ($readonly && $status === SecurityCheckProcess::STATUS_ARCHIVED): ?>
<div class="notice" data-variant="info" role="status">
<p><?php e(t('This security check is archived and read-only.')); ?></p>
</div>
<?php endif; ?>
<!-- Checklist -->
<form method="post" id="security-check-form" data-app-component="security-check-workspace">
<div class="security-steps">
<?php foreach ($steps as $index => $step):
$key = (string) ($step['key'] ?? '');
$kind = (string) ($step['kind'] ?? SecurityCheckProcess::KIND_STEP);
$stepNumber = $index + 1;
?>
<?php if ($kind === SecurityCheckProcess::KIND_TECH_CHECKLIST): ?>
<!-- Step: technical checklist (per product) -->
<article class="security-step security-step-tech">
<header class="security-step-head">
<span class="security-step-number"><?php e((string) $stepNumber); ?></span>
<div>
<h3><?php e(t((string) ($step['label'] ?? ''))); ?></h3>
<p class="app-muted"><?php e(t((string) ($step['description'] ?? ''))); ?></p>
</div>
<?php if (!empty($progress['step6_done'])): ?>
<span class="badge" data-variant="success"><?php e(t('Complete')); ?></span>
<?php endif; ?>
</header>
<?php if ($techItems === []): ?>
<p class="app-muted security-step-empty"><?php e(t('This product has no technical checklist items defined yet.')); ?></p>
<?php else: ?>
<ul class="security-tech-list">
<?php
$snapshotItems = is_array($check['tech_schema_snapshot']['items'] ?? null) ? $check['tech_schema_snapshot']['items'] : [];
foreach ($snapshotItems as $item):
if (!is_array($item)) { continue; }
$itemType = (string) ($item['type'] ?? 'check');
if ($itemType === 'section'): ?>
<li class="security-tech-section"><?php e((string) ($item['label'] ?? '')); ?></li>
<?php else:
$itemKey = (string) ($item['key'] ?? '');
if ($itemKey === '') { continue; }
$entry = is_array($techState[$itemKey] ?? null) ? $techState[$itemKey] : [];
$done = !empty($entry['done']);
$note = (string) ($entry['note'] ?? '');
$meta = $completionMeta($entry);
?>
<li class="security-tech-item<?php if ($done): ?> is-done<?php endif; ?>">
<label class="security-check-toggle">
<input type="checkbox" name="tech[<?php e($itemKey); ?>][done]" value="1"<?php if ($done): ?> checked<?php endif; ?><?php if ($readonly): ?> disabled<?php endif; ?>>
<span class="security-tech-label">
<?php e((string) ($item['label'] ?? '')); ?>
<?php if (trim((string) ($item['hint'] ?? '')) !== ''): ?>
<small class="app-muted security-tech-hint"><?php e((string) $item['hint']); ?></small>
<?php endif; ?>
</span>
</label>
<?php if ($meta !== ''): ?><span class="security-completion-meta"><i class="bi bi-check2-circle"></i> <?php e($meta); ?></span><?php endif; ?>
<?php if (trim((string) ($item['markdown_html'] ?? '')) !== ''):
$markdownHtml = (string) $item['markdown_html'];
require __DIR__ . '/../../../templates/tech-markdown.phtml';
endif; ?>
<input type="text" class="security-item-note" name="tech[<?php e($itemKey); ?>][note]" value="<?php e($note); ?>" placeholder="<?php e(t('Note (optional)')); ?>"<?php if ($readonly): ?> disabled<?php endif; ?>>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</article>
<?php else:
$entry = is_array($processState[$key] ?? null) ? $processState[$key] : [];
$done = !empty($entry['done']);
$note = (string) ($entry['note'] ?? '');
$meta = $completionMeta($entry);
?>
<article class="security-step<?php if ($done): ?> is-done<?php endif; ?>">
<header class="security-step-head">
<span class="security-step-number"><?php e((string) $stepNumber); ?></span>
<label class="security-check-toggle security-step-toggle">
<input type="checkbox" name="step[<?php e($key); ?>][done]" value="1"<?php if ($done): ?> checked<?php endif; ?><?php if ($readonly): ?> disabled<?php endif; ?>>
<span>
<strong><?php e(t((string) ($step['label'] ?? ''))); ?></strong>
<small class="app-muted"><?php e(t((string) ($step['description'] ?? ''))); ?></small>
</span>
</label>
<?php if ($meta !== ''): ?><span class="security-completion-meta"><i class="bi bi-check2-circle"></i> <?php e($meta); ?></span><?php endif; ?>
</header>
<?php
$stepFields = is_array($step['fields'] ?? null) ? $step['fields'] : [];
if ($stepFields !== []):
$fieldValues = is_array($entry['fields'] ?? null) ? $entry['fields'] : [];
$hasRequired = false;
?>
<div class="security-step-fields">
<?php foreach ($stepFields as $field):
$fkey = (string) ($field['key'] ?? '');
if ($fkey === '') { continue; }
$ftype = (string) ($field['type'] ?? SecurityCheckProcess::FIELD_TEXTAREA);
$isDatetime = $ftype === SecurityCheckProcess::FIELD_DATETIME;
$fieldRequired = ($field['required'] ?? false) === true;
if ($fieldRequired) { $hasRequired = true; }
$fval = (string) ($fieldValues[$fkey] ?? '');
$fname = 'step[' . $key . '][fields][' . $fkey . ']';
$fid = 'security-field-' . $key . '-' . $fkey;
?>
<div class="security-step-field<?php if ($isDatetime): ?> security-step-field-datetime<?php endif; ?>">
<label for="<?php e($fid); ?>"><?php e(t((string) ($field['label'] ?? ''))); ?><?php if ($fieldRequired): ?> <span class="security-form-required" aria-hidden="true">*</span><?php endif; ?></label>
<?php if ($isDatetime): ?>
<input type="datetime-local" id="<?php e($fid); ?>" name="<?php e($fname); ?>" value="<?php e($fval); ?>"<?php if ($fieldRequired): ?> data-security-required="1"<?php endif; ?><?php if ($readonly): ?> disabled<?php endif; ?>>
<?php else: ?>
<textarea id="<?php e($fid); ?>" name="<?php e($fname); ?>" rows="2"<?php if ($fieldRequired): ?> data-security-required="1"<?php endif; ?><?php if ($readonly): ?> disabled<?php endif; ?>><?php e($fval); ?></textarea>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php if ($hasRequired): ?>
<p class="security-step-gate-hint" data-security-gate-hint hidden>
<i class="bi bi-info-circle"></i> <?php e(t('Fill in all required fields to complete this step.')); ?>
</p>
<?php endif; ?>
<?php endif; ?>
<input type="text" class="security-item-note" name="step[<?php e($key); ?>][note]" value="<?php e($note); ?>" placeholder="<?php e(t('Note (optional)')); ?>"<?php if ($readonly): ?> disabled<?php endif; ?>>
<?php if ($key === SecurityCheckProcess::STEP_REPORT): ?>
<div class="security-report-action">
<?php if ($canGenerateReport && $reportPdfUrl !== ''): ?>
<a href="<?php e($reportPdfUrl); ?>" class="secondary outline small" target="_blank" rel="noopener">
<i class="bi bi-file-earmark-pdf" aria-hidden="true"></i> <?php e(t('Generate PDF customer report')); ?>
</a>
<p class="app-muted security-report-hint"><?php e(t('Opens in a new tab and reflects the last saved state.')); ?></p>
<?php else: ?>
<button type="button" class="secondary outline small" disabled>
<i class="bi bi-file-earmark-pdf" aria-hidden="true"></i> <?php e(t('Generate PDF customer report')); ?>
</button>
<p class="app-muted security-report-hint"><i class="bi bi-lock" aria-hidden="true"></i> <?php e(t('Complete and save all previous steps to enable the customer report.')); ?></p>
<?php endif; ?>
</div>
<?php endif; ?>
</article>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php if (!$readonly): ?>
<div class="security-form-actions">
<button type="submit" name="action" value="save" class="primary app-action-success"><?php e(t('Save')); ?></button>
</div>
<?php endif; ?>
<?php \MintyPHP\Session::getCsrfInput(); ?>
</form>
<?php if ($canManage): ?>
<!-- Danger zone -->
<div class="security-danger-zone">
<div class="security-danger-zone-inner">
<h3><?php e(t('Danger zone')); ?></h3>
<div class="security-danger-actions">
<form method="post">
<?php \MintyPHP\Session::getCsrfInput(); ?>
<?php if ($status === SecurityCheckProcess::STATUS_ARCHIVED): ?>
<button type="submit" name="action" value="unarchive" class="secondary outline small"><i class="bi bi-arrow-counterclockwise"></i> <?php e(t('Reopen check')); ?></button>
<?php else: ?>
<button type="submit" name="action" value="archive" class="secondary outline small"
data-confirm-message="<?php e(t('Archive this security check? It will become read-only.')); ?>"
data-confirm-variant="warning"><i class="bi bi-archive"></i> <?php e(t('Archive check')); ?></button>
<?php endif; ?>
</form>
<form method="post">
<?php \MintyPHP\Session::getCsrfInput(); ?>
<button type="submit" name="action" value="delete" class="danger outline small"
data-confirm-message="<?php e(t('Delete this security check? This cannot be undone.')); ?>"
data-confirm-variant="danger"><i class="bi bi-trash3"></i> <?php e(t('Delete check')); ?></button>
</form>
</div>
</div>
</div>
<?php endif; ?>
</section>
</div>