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>
123 lines
5.2 KiB
PHP
123 lines
5.2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/db.php';
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
require_once __DIR__ . '/includes/layout.php';
|
|
|
|
auth_check();
|
|
|
|
$message = '';
|
|
|
|
// Suppression d'un email traité
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_source'])) {
|
|
$id = (int)$_POST['delete_source'];
|
|
$st = db()->prepare('SELECT sf.title, CONCAT(sf.file_name) as fname, GROUP_CONCAT(f.path) as fpaths
|
|
FROM source_file sf LEFT JOIN files f ON sf.id = f.source_file_id
|
|
WHERE sf.id = ? GROUP BY sf.id');
|
|
$st->execute([$id]);
|
|
$row = $st->fetch();
|
|
if ($row) {
|
|
if ($row['fpaths']) {
|
|
foreach (explode(',', $row['fpaths']) as $path) {
|
|
if (file_exists($path)) unlink($path);
|
|
}
|
|
}
|
|
db()->prepare('DELETE FROM source_file WHERE id = ?')->execute([$id]);
|
|
flash('success', "Entrée « " . htmlspecialchars($row['title']) . " » supprimée.");
|
|
}
|
|
header('Location: /');
|
|
exit;
|
|
}
|
|
|
|
$rows = db()->query(
|
|
'SELECT sf.id, sf.title, sf.sender, sf.date_processing, a.username,
|
|
GROUP_CONCAT(f.id, ":", f.file_name, ":", f.path ORDER BY f.id SEPARATOR "|") as files
|
|
FROM source_file sf
|
|
LEFT JOIN accounts a ON sf.account_id = a.id
|
|
LEFT JOIN files f ON sf.id = f.source_file_id
|
|
GROUP BY sf.id
|
|
ORDER BY sf.date_processing DESC'
|
|
)->fetchAll();
|
|
|
|
html_head('Courriers');
|
|
html_navbar('mail');
|
|
?>
|
|
<div class="container-fluid">
|
|
<?php flash_render(); ?>
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h5 class="mb-0"><i class="bi bi-envelope-fill me-2"></i>Courriers traités</h5>
|
|
<span class="badge bg-secondary"><?= count($rows) ?> entrée(s)</span>
|
|
</div>
|
|
|
|
<?php if (empty($rows)): ?>
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle me-2"></i>Aucun courrier traité pour l'instant.
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="card shadow-sm">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Compte</th>
|
|
<th>Sujet</th>
|
|
<th>Expéditeur</th>
|
|
<th>Pièces jointes</th>
|
|
<th class="text-center">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($rows as $r): ?>
|
|
<tr>
|
|
<td class="text-nowrap text-muted small">
|
|
<?= htmlspecialchars(date('d/m/Y H:i', strtotime($r['date_processing']))) ?>
|
|
</td>
|
|
<td>
|
|
<?php if ($r['username']): ?>
|
|
<span class="badge bg-primary"><?= htmlspecialchars($r['username']) ?></span>
|
|
<?php else: ?>
|
|
<span class="text-muted">—</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td><?= htmlspecialchars($r['title'] ?? '(sans sujet)') ?></td>
|
|
<td class="small text-muted"><?= htmlspecialchars($r['sender'] ?? '') ?></td>
|
|
<td>
|
|
<?php if ($r['files']): ?>
|
|
<?php foreach (explode('|', $r['files']) as $f): ?>
|
|
<?php [$fid, $fname, $fpath] = array_pad(explode(':', $f, 3), 3, ''); ?>
|
|
<?php if (file_exists($fpath)): ?>
|
|
<a href="/mail/download.php?id=<?= (int)$fid ?>" class="badge bg-info text-decoration-none me-1">
|
|
<i class="bi bi-download me-1"></i><?= htmlspecialchars(substr($fname, 0, 20)) ?>
|
|
</a>
|
|
<?php else: ?>
|
|
<span class="badge bg-secondary me-1" title="Fichier introuvable">
|
|
<?= htmlspecialchars(substr($fname, 0, 20)) ?>
|
|
</span>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<span class="text-muted small">Aucune pièce jointe</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="text-center">
|
|
<form method="post" onsubmit="return confirm('Supprimer cette entrée ?')">
|
|
<input type="hidden" name="delete_source" value="<?= $r['id'] ?>">
|
|
<button class="btn btn-sm btn-outline-danger">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<script>
|
|
setTimeout(() => location.reload(), 30000);
|
|
</script>
|
|
<?php html_foot(); ?>
|