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 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(), ]); } }