forked from fa/breadcrumb-the-shire
124 lines
6.0 KiB
PHTML
124 lines
6.0 KiB
PHTML
<?php
|
|
|
|
/**
|
|
* Customer-facing security check report (Dompdf).
|
|
*
|
|
* Hydrated as an isolated HTML string by SecurityReportPdfService — it only
|
|
* sees $report (the flat, pre-built context). All dynamic values are escaped
|
|
* with e(); labels go through t() so the report follows the request locale.
|
|
*
|
|
* @var array<string, mixed> $report
|
|
*/
|
|
$report = is_array($report ?? null) ? $report : [];
|
|
$summary = is_array($report['summary'] ?? null) ? $report['summary'] : [];
|
|
$steps = is_array($report['steps'] ?? null) ? $report['steps'] : [];
|
|
$techSections = is_array($report['tech_sections'] ?? null) ? $report['tech_sections'] : [];
|
|
|
|
$percent = (int) ($summary['percent'] ?? 0);
|
|
$techDone = (int) ($summary['tech_done'] ?? 0);
|
|
$techTotal = (int) ($summary['tech_total'] ?? 0);
|
|
$appName = trim((string) ($report['app_name'] ?? ''));
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?php e((string) (\MintyPHP\I18n::$locale ?? 'en')); ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title><?php e((string) ($report['title'] ?? '')); ?></title>
|
|
<style>
|
|
* { box-sizing: border-box; }
|
|
body { font-family: "DejaVu Sans", Arial, sans-serif; color: #1a1a1a; font-size: 12px; line-height: 1.45; margin: 0; }
|
|
h1 { font-size: 20px; margin: 0 0 2px; }
|
|
h2 { font-size: 14px; margin: 22px 0 8px; padding-bottom: 4px; border-bottom: 1px solid #e2e2e2; }
|
|
.muted { color: #6a6a6a; }
|
|
.header { border-bottom: 2px solid #1a1a1a; padding-bottom: 12px; margin-bottom: 16px; }
|
|
.header-logo { max-height: 48px; max-width: 200px; margin-bottom: 10px; }
|
|
table { width: 100%; border-collapse: collapse; }
|
|
.meta td { padding: 3px 0; vertical-align: top; }
|
|
.meta td.label { color: #6a6a6a; width: 38%; }
|
|
.summary { margin: 6px 0 4px; font-size: 13px; }
|
|
.bar { height: 10px; background: #ececec; border-radius: 5px; overflow: hidden; margin-top: 6px; }
|
|
.bar-fill { height: 10px; background: #2e7d32; }
|
|
.checklist td { padding: 6px 8px; border-bottom: 1px solid #ededed; vertical-align: top; }
|
|
.checklist td.state { width: 70px; white-space: nowrap; }
|
|
.section-row td { background: #f5f5f5; font-weight: bold; padding: 6px 8px; }
|
|
.ok { color: #2e7d32; font-weight: bold; }
|
|
.pending { color: #b26a00; font-weight: bold; }
|
|
.note { color: #6a6a6a; font-size: 11px; margin-top: 2px; }
|
|
.footer { margin-top: 26px; padding-top: 8px; border-top: 1px solid #e2e2e2; color: #8a8a8a; font-size: 10px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<img src="<?php e((string) ($report['logo_data_uri'] ?? '')); ?>" alt="" class="header-logo">
|
|
<h1><?php e((string) ($report['title'] ?? '')); ?></h1>
|
|
<div class="muted"><?php e(t('Generated on')); ?> <?php e((string) ($report['generated_at'] ?? '')); ?></div>
|
|
</div>
|
|
|
|
<table class="meta">
|
|
<tr><td class="label"><?php e(t('Customer')); ?></td><td><?php e((string) ($report['customer_name'] ?? '')); ?><?php if (($report['customer_no'] ?? '') !== ''): ?> <span class="muted">(<?php e((string) $report['customer_no']); ?>)</span><?php endif; ?></td></tr>
|
|
<tr><td class="label"><?php e(t('Domain')); ?></td><td><?php e((string) ($report['domain'] ?? '')); ?></td></tr>
|
|
<tr><td class="label"><?php e(t('Software product')); ?></td><td><?php e((string) ($report['product'] ?? '')); ?></td></tr>
|
|
<tr><td class="label"><?php e(t('Status')); ?></td><td><?php e((string) ($report['status_label'] ?? '')); ?></td></tr>
|
|
</table>
|
|
|
|
<h2><?php e(t('Result')); ?></h2>
|
|
<div class="summary"><?php e(t('%d of %d checks completed', $techDone, $techTotal)); ?> (<?php e((string) $percent); ?>%)</div>
|
|
<div class="bar"><div class="bar-fill" style="width: <?php e((string) $percent); ?>%;"></div></div>
|
|
|
|
<h2><?php e(t('Technical checklist')); ?></h2>
|
|
<?php if ($techSections === []): ?>
|
|
<p class="muted"><?php e(t('This product has no technical checklist items defined yet.')); ?></p>
|
|
<?php else: ?>
|
|
<table class="checklist">
|
|
<?php foreach ($techSections as $section): ?>
|
|
<?php if (trim((string) ($section['label'] ?? '')) !== ''): ?>
|
|
<tr class="section-row"><td colspan="2"><?php e((string) $section['label']); ?></td></tr>
|
|
<?php endif; ?>
|
|
<?php foreach (($section['items'] ?? []) as $item): ?>
|
|
<tr>
|
|
<td class="state">
|
|
<?php if (!empty($item['done'])): ?>
|
|
<span class="ok">✓ <?php e(t('Completed')); ?></span>
|
|
<?php else: ?>
|
|
<span class="pending"><?php e(t('Not completed')); ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php e((string) ($item['label'] ?? '')); ?>
|
|
<?php if (trim((string) ($item['note'] ?? '')) !== ''): ?>
|
|
<div class="note"><?php e((string) $item['note']); ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endforeach; ?>
|
|
</table>
|
|
<?php endif; ?>
|
|
|
|
<h2><?php e(t('Process')); ?></h2>
|
|
<table class="checklist">
|
|
<?php foreach ($steps as $step): ?>
|
|
<tr>
|
|
<td class="state">
|
|
<?php if (!empty($step['done'])): ?>
|
|
<span class="ok">✓ <?php e(t('Completed')); ?></span>
|
|
<?php else: ?>
|
|
<span class="pending"><?php e(t('Open')); ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php e((string) ($step['number'] ?? '')); ?>. <?php e((string) ($step['label'] ?? '')); ?>
|
|
<?php if (trim((string) ($step['completed_at'] ?? '')) !== ''): ?>
|
|
<span class="muted">· <?php e((string) $step['completed_at']); ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</table>
|
|
|
|
<div class="footer">
|
|
<?php if ($appName !== ''): ?><?php e($appName); ?> · <?php endif; ?><?php e((string) ($report['title'] ?? '')); ?> · <?php e((string) ($report['generated_at'] ?? '')); ?>
|
|
</div>
|
|
</body>
|
|
</html>
|