mailwolt/app/Livewire/Ui/Nx/Mail/QuarantineList.php

130 lines
4.5 KiB
PHP

<?php
namespace App\Livewire\Ui\Nx\Mail;
use Illuminate\Pagination\LengthAwarePaginator;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;
#[Layout('layouts.dvx')]
#[Title('Quarantäne · Mailwolt')]
class QuarantineList extends Component
{
use WithPagination;
#[Url(as: 'filter', keep: true)]
public string $filter = 'suspicious';
#[Url(as: 'q', keep: true)]
public string $search = '';
public int $perPage = 25;
public int $rows = 500;
#[On('quarantine:updated')]
public function refresh(): void {}
public function updatedFilter(): void { $this->resetPage(); }
public function updatedSearch(): void { $this->resetPage(); }
public function openMessage(string $msgId): void
{
$this->dispatch('openModal',
component: 'ui.nx.mail.modal.quarantine-message-modal',
arguments: ['msgId' => $msgId]
);
}
public function render()
{
$all = $this->fetchHistory();
$suspicious = array_values(array_filter($all, fn($m) => $m['action'] !== 'no action'));
$counts = [
'all' => count($all),
'suspicious' => count($suspicious),
'reject' => count(array_filter($all, fn($m) => $m['action'] === 'reject')),
'add header' => count(array_filter($all, fn($m) => $m['action'] === 'add header')),
'greylist' => count(array_filter($all, fn($m) => $m['action'] === 'greylist')),
];
$messages = match($this->filter) {
'suspicious' => $suspicious,
'all' => $all,
default => array_values(array_filter($all, fn($m) => $m['action'] === $this->filter)),
};
if ($this->search !== '') {
$s = strtolower($this->search);
$messages = array_values(array_filter($messages, fn($m) =>
str_contains(strtolower($m['from'] ?? ''), $s) ||
str_contains(strtolower($m['rcpt'] ?? ''), $s) ||
str_contains(strtolower($m['subject'] ?? ''), $s)
));
}
$total = count($messages);
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$paged = new LengthAwarePaginator(
array_slice($messages, ($currentPage - 1) * $this->perPage, $this->perPage),
$total,
$this->perPage,
$currentPage,
['path' => request()->url()]
);
return view('livewire.ui.nx.mail.quarantine-list', [
'messages' => $paged,
'counts' => $counts,
]);
}
// ── helpers ──────────────────────────────────────────────────────────────
public function fetchHistory(): array
{
$password = env('RSPAMD_PASSWORD', '');
$opts = [
'http' => [
'timeout' => 3,
'ignore_errors' => true,
'header' => $password !== '' ? "Password: {$password}\r\n" : '',
],
];
$ctx = stream_context_create($opts);
$raw = @file_get_contents("http://127.0.0.1:11334/history?rows={$this->rows}", false, $ctx);
if (!$raw) return [];
$data = json_decode($raw, true);
if (!is_array($data)) return [];
$items = $data['rows'] ?? (isset($data[0]) ? $data : []);
return array_map(function ($r) {
$rcpt = $r['rcpt'] ?? [];
if (is_array($rcpt)) $rcpt = implode(', ', $rcpt);
return [
'id' => $r['scan_id'] ?? ($r['id'] ?? uniqid('q_')),
'msg_id' => $r['message-id'] ?? '—',
'from' => $r['from'] ?? $r['sender'] ?? '—',
'rcpt' => $rcpt ?: '—',
'subject' => $r['subject'] ?? '(kein Betreff)',
'score' => round((float)($r['score'] ?? 0), 2),
'required' => round((float)($r['required_score'] ?? 15), 2),
'action' => $r['action'] ?? 'unknown',
'time' => (int)($r['unix_time'] ?? $r['time'] ?? 0),
'size' => (int)($r['size'] ?? 0),
'symbols' => array_keys($r['symbols'] ?? []),
'ip' => $r['ip'] ?? '—',
];
}, $items);
}
}