169 lines
6.4 KiB
PHP
169 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Admin;
|
|
|
|
use App\Services\Mail\MailLane;
|
|
use App\Support\Settings;
|
|
use Illuminate\Support\Facades\Queue;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Component;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* Der Notschalter und die Sicht auf die drei Versandspuren.
|
|
*
|
|
* Eigene Seite statt eines fünften Abschnitts auf admin/mail (App\Livewire\
|
|
* Admin\Mail): dort liegen Server, Postfächer, Zwecke und Wegwahl bereits
|
|
* „alles in einer Wurst" — eine weitere Scheibe wäre keine Verbesserung. Es
|
|
* ist auch inhaltlich eine andere Art Seite: admin/mail RICHTET EIN (einmal,
|
|
* und es gilt), diese hier BEOBACHTET UND GREIFT EIN (laufend, im Ernstfall
|
|
* mit einem Klick) — deshalb steht sie in der Navigation unter „Betrieb", wo
|
|
* schon Provisioning, Wartungen und Störungen stehen, nicht unter „System".
|
|
*
|
|
* Dieselbe Fähigkeit wie admin/mail (`mail.manage`): wer die Postfächer und
|
|
* den Server sehen und ändern darf, darf auch die Spuren sehen und die
|
|
* Drossel abstellen.
|
|
*/
|
|
#[Layout('layouts.admin')]
|
|
class MailPace extends Component
|
|
{
|
|
public bool $enabled = true;
|
|
|
|
public int $urgentCount = 30;
|
|
|
|
public int $urgentMinutes = 5;
|
|
|
|
public int $calmCount = 20;
|
|
|
|
public int $calmMinutes = 10;
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->authorize('mail.manage');
|
|
|
|
$this->enabled = Settings::bool('mail.pace.enabled', true);
|
|
$this->urgentCount = (int) Settings::get('mail.pace.urgent.count', 30);
|
|
$this->urgentMinutes = (int) Settings::get('mail.pace.urgent.minutes', 5);
|
|
$this->calmCount = (int) Settings::get('mail.pace.calm.count', 20);
|
|
$this->calmMinutes = (int) Settings::get('mail.pace.calm.minutes', 10);
|
|
}
|
|
|
|
/**
|
|
* Der Notschalter: nach dem Muster von Admin\Plans::toggleSales() — eine
|
|
* Methode, eine Rückmeldung, kein Bestätigungsmodal. Er ist umkehrbar,
|
|
* derselbe Klick legt ihn zurück.
|
|
*/
|
|
public function togglePace(): void
|
|
{
|
|
$this->authorize('mail.manage');
|
|
|
|
$this->enabled = ! $this->enabled;
|
|
Settings::set('mail.pace.enabled', $this->enabled);
|
|
|
|
$this->dispatch('notify', message: __($this->enabled ? 'mail_pace.enabled_on_notice' : 'mail_pace.enabled_off_notice'));
|
|
}
|
|
|
|
/**
|
|
* Die beiden Kontingente speichern.
|
|
*
|
|
* `min:1` auf allen vier Feldern ist die zweite Hälfte der Untergrenze aus
|
|
* MailPaceServiceProvider::mindestensEins() — die liest nur ab, was hier
|
|
* gar nicht erst gespeichert werden darf. Ohne diese Prüfung käme eine
|
|
* eingetippte 0 ungeprüft bis in die Einstellung durch und flöge erst beim
|
|
* nächsten Auftrag an der Lesestelle auf, nachdem der Betreiber schon
|
|
* „gespeichert" gesehen hat — ein Kontingent von 0 heißt dort: jede Mail
|
|
* wird endlos zurückgelegt, ein Fenster von 0 Minuten schaltet die Drossel
|
|
* still ab.
|
|
*/
|
|
public function savePace(): void
|
|
{
|
|
$this->authorize('mail.manage');
|
|
|
|
$data = $this->validate([
|
|
'urgentCount' => ['required', 'integer', 'min:1'],
|
|
'urgentMinutes' => ['required', 'integer', 'min:1'],
|
|
'calmCount' => ['required', 'integer', 'min:1'],
|
|
'calmMinutes' => ['required', 'integer', 'min:1'],
|
|
]);
|
|
|
|
Settings::set('mail.pace.urgent.count', $data['urgentCount']);
|
|
Settings::set('mail.pace.urgent.minutes', $data['urgentMinutes']);
|
|
Settings::set('mail.pace.calm.count', $data['calmCount']);
|
|
Settings::set('mail.pace.calm.minutes', $data['calmMinutes']);
|
|
|
|
$this->dispatch('notify', message: __('mail_pace.saved'));
|
|
}
|
|
|
|
/**
|
|
* Eine Mailklasse in eine andere Spur verschieben.
|
|
*
|
|
* Ein Ziel außerhalb der drei bekannten Spuren kommt nur über einen
|
|
* manuellen Aufruf zustande — kein <select> im DOM bietet eines an — und
|
|
* wird verworfen statt in die Einstellungen zu wandern, wo `MailLane::
|
|
* for()` es beim nächsten Lesen ohnehin still auf „ruhig" zurückfallen
|
|
* ließe, ohne dass der Betreiber sähe, dass sein Klick nichts bewirkt hat.
|
|
*/
|
|
public function move(string $mailableClass, string $lane): void
|
|
{
|
|
$this->authorize('mail.manage');
|
|
|
|
if (! in_array($lane, [MailLane::DIRECT, MailLane::URGENT, MailLane::CALM], true)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
MailLane::assign($mailableClass, $lane);
|
|
} catch (RuntimeException) {
|
|
// Gesperrt: der Server lehnt so oder so ab (Task 1), das Schloss in
|
|
// der Ansicht ist nur die Höflichkeit davor. Wer trotzdem hier
|
|
// ankommt — kein <select> bietet einer gesperrten Klasse eines an,
|
|
// also nur ein manueller Aufruf — bekommt eine Meldung statt eines
|
|
// Serverfehlers.
|
|
$this->dispatch('notify', message: __('mail_pace.locked_notice'));
|
|
|
|
return;
|
|
}
|
|
|
|
$this->dispatch('notify', message: __('mail_pace.moved'));
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
// Je Spur: die Warteschlange, die App\Mail\Concerns\RidesALane
|
|
// tatsächlich befüllt (Task 2) — derselbe Name, den auch der Arbeiter
|
|
// in docker-compose.yml abhört (Task 4). Im echten Betrieb (Redis)
|
|
// eine ehrliche Zahl aus der tatsächlichen Liste; unter der
|
|
// Sync-Warteschlange, die die Testsuite erzwingt, immer 0, weil dort
|
|
// nichts je wartet statt verschickt zu werden — dort ist die Zahl
|
|
// ebenso ehrlich, nur bedeutungslos für einen Testfall, der einen
|
|
// Rückstand nachstellen wollte.
|
|
$lanes = [
|
|
[
|
|
'key' => MailLane::DIRECT,
|
|
'throttled' => false,
|
|
'waiting' => Queue::size(MailLane::DIRECT),
|
|
],
|
|
[
|
|
'key' => MailLane::URGENT,
|
|
'throttled' => true,
|
|
'waiting' => Queue::size(MailLane::URGENT),
|
|
'countField' => 'urgentCount',
|
|
'minutesField' => 'urgentMinutes',
|
|
],
|
|
[
|
|
'key' => MailLane::CALM,
|
|
'throttled' => true,
|
|
'waiting' => Queue::size(MailLane::CALM),
|
|
'countField' => 'calmCount',
|
|
'minutesField' => 'calmMinutes',
|
|
],
|
|
];
|
|
|
|
return view('livewire.admin.mail-pace', [
|
|
'lanes' => $lanes,
|
|
'laneOptions' => [MailLane::DIRECT, MailLane::URGENT, MailLane::CALM],
|
|
'assignments' => MailLane::all(),
|
|
]);
|
|
}
|
|
}
|