init: projet complet copymail pour Raspberry Pi
Stack: Nginx + PHP 8.2 + MariaDB + Postfix + Dovecot + Samba - install.sh: script installation automatisé pour RPi OS Bookworm - Interface web: visionneuse mails + admin (comptes, domaine, dashboard) - Chaque compte mail génère automatiquement un share Samba - Processeur cron: extraction pièces jointes via zbateson/mail-mime-parser - Zéro injection SQL (PDO + prepared statements) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
116
web/admin/index.php
Normal file
116
web/admin/index.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
require_once __DIR__ . '/../includes/layout.php';
|
||||
|
||||
auth_check();
|
||||
|
||||
$services = [
|
||||
'postfix' => ['Postfix (SMTP)', 'bi-envelope-at'],
|
||||
'dovecot' => ['Dovecot (IMAP)', 'bi-inbox'],
|
||||
'smbd' => ['Samba (SMB)', 'bi-folder-symlink'],
|
||||
'nginx' => ['Nginx (Web)', 'bi-globe'],
|
||||
'mariadb' => ['MariaDB', 'bi-database'],
|
||||
];
|
||||
|
||||
$statuses = [];
|
||||
foreach ($services as $svc => [$label, $icon]) {
|
||||
$out = shell_exec("systemctl is-active " . escapeshellarg($svc) . " 2>/dev/null");
|
||||
$statuses[$svc] = ['label' => $label, 'icon' => $icon, 'active' => trim($out) === 'active'];
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'accounts' => (int)db()->query('SELECT COUNT(*) FROM accounts WHERE active=1')->fetchColumn(),
|
||||
'emails' => (int)db()->query('SELECT COUNT(*) FROM source_file')->fetchColumn(),
|
||||
'files' => (int)db()->query('SELECT COUNT(*) FROM files')->fetchColumn(),
|
||||
];
|
||||
|
||||
$domain = cfg('domain');
|
||||
$last5 = db()->query(
|
||||
'SELECT sf.title, sf.sender, sf.date_processing, a.username
|
||||
FROM source_file sf LEFT JOIN accounts a ON sf.account_id = a.id
|
||||
ORDER BY sf.date_processing DESC LIMIT 5'
|
||||
)->fetchAll();
|
||||
|
||||
html_head('Tableau de bord');
|
||||
html_navbar('status');
|
||||
?>
|
||||
<div class="container-fluid">
|
||||
<h5 class="mb-4"><i class="bi bi-activity me-2"></i>Tableau de bord</h5>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-0 shadow-sm text-center">
|
||||
<div class="card-body">
|
||||
<div class="display-6 fw-bold text-primary"><?= $stats['accounts'] ?></div>
|
||||
<div class="text-muted small">Comptes actifs</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-0 shadow-sm text-center">
|
||||
<div class="card-body">
|
||||
<div class="display-6 fw-bold text-success"><?= $stats['emails'] ?></div>
|
||||
<div class="text-muted small">Emails traités</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card border-0 shadow-sm text-center">
|
||||
<div class="card-body">
|
||||
<div class="display-6 fw-bold text-info"><?= $stats['files'] ?></div>
|
||||
<div class="text-muted small">Fichiers extraits</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Services -->
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-server me-2"></i>État des services</span>
|
||||
<small class="text-muted">Domaine : <strong><?= htmlspecialchars($domain) ?></strong></small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<?php foreach ($statuses as $svc => $s): ?>
|
||||
<div class="col-md-4">
|
||||
<div class="d-flex align-items-center p-2 rounded border <?= $s['active'] ? 'border-success bg-success bg-opacity-10' : 'border-danger bg-danger bg-opacity-10' ?>">
|
||||
<i class="bi <?= $s['icon'] ?> fs-4 me-3 <?= $s['active'] ? 'text-success' : 'text-danger' ?>"></i>
|
||||
<div>
|
||||
<div class="fw-semibold"><?= $s['label'] ?></div>
|
||||
<span class="badge <?= $s['active'] ? 'bg-success' : 'bg-danger' ?>"><?= $s['active'] ? 'actif' : 'arrêté' ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Derniers emails -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header"><i class="bi bi-clock-history me-2"></i>Derniers courriers reçus</div>
|
||||
<?php if (empty($last5)): ?>
|
||||
<div class="card-body text-muted">Aucun courrier traité.</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm mb-0">
|
||||
<thead class="table-light"><tr><th>Date</th><th>Compte</th><th>Sujet</th><th>Expéditeur</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($last5 as $r): ?>
|
||||
<tr>
|
||||
<td class="small text-muted"><?= date('d/m H:i', strtotime($r['date_processing'])) ?></td>
|
||||
<td><span class="badge bg-primary"><?= htmlspecialchars($r['username'] ?? '?') ?></span></td>
|
||||
<td><?= htmlspecialchars($r['title'] ?? '—') ?></td>
|
||||
<td class="small text-muted"><?= htmlspecialchars($r['sender'] ?? '') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php html_foot(); ?>
|
||||
Reference in New Issue
Block a user